支付宝接入

前言

所有vue接口全部在src/api/api.js文件下

代码已上传至github:https://github.com/kalipoison/fresh-market

此项目仅学习用途

要求

Package Version


certifi 2020.4.5.1
chardet 3.0.4
coreapi 2.3.1
coreschema 0.0.4
Django 1.11.3
django-cors-headers 2.1.0
django-crispy-forms 1.6.1
django-filter 1.0.4
django-formtools 2.0
django-guardian 1.4.9
django-reversion 2.0.9
djangorestframework 3.6.3
djangorestframework-jwt 1.11.0
future 0.16.0
httplib2 0.9.2
idna 2.9
itypes 1.2.0
Jinja2 2.11.2
Markdown 2.6.8
MarkupSafe 1.1.1
mysqlclient 1.3.10
olefile 0.46
Pillow 4.2.1
pip 20.0.2
pycryptodome 3.9.7
PyJWT 1.7.1
pytz 2019.3
requests 2.23.0
setuptools 46.1.3
six 1.10.0
uritemplate 3.0.1
urllib3 1.25.9
wheel 0.34.2
XlsxWriter 0.9.8
xlwt 1.2.0

注意:一定要填写下面代码中的APPID,否则页面将无法正常做出与支付宝相关操作

流程

trade文件夹下serializers.py代码如下:

serializers.py


import time
from rest_framework import serializersfrom goods.models import Goods
from .models import ShoppingCart, OrderInfo, OrderGoods
from goods.serializers import GoodsSerializer
from utils.alipay import AliPay
from Mxshop.settings import private_key_path, ali_pub_key_pathclass ShopCartDetailSerializer(serializers.ModelSerializer):goods = GoodsSerializer(many=False, read_only=True)class Meta:model = ShoppingCartfields = ("goods", "nums")class ShopCartSerializer(serializers.Serializer):user = serializers.HiddenField(default=serializers.CurrentUserDefault())nums = serializers.IntegerField(required=True, label="数量",min_value=1,error_messages={"min_value":"商品数量不能小于一","required": "请选择购买数量"})goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())def create(self, validated_data):user = self.context["request"].usernums = validated_data["nums"]goods = validated_data["goods"]existed = ShoppingCart.objects.filter(user=user, goods=goods)if existed:existed = existed[0]existed.nums += numsexisted.save()else:existed = ShoppingCart.objects.create(**validated_data)return existeddef update(self, instance, validated_data):#修改商品数量instance.nums = validated_data["nums"]instance.save()return instanceclass OrderGoodsSerialzier(serializers.ModelSerializer):goods = GoodsSerializer(many=False)class Meta:model = OrderGoodsfields = "__all__"class OrderDetailSerializer(serializers.ModelSerializer):goods = OrderGoodsSerialzier(many=True)alipay_url = serializers.SerializerMethodField(read_only=True)def get_alipay_url(self, obj):alipay = AliPay(# 填写自己的appid(必填)appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")url = alipay.direct_pay(subject=obj.order_sn,out_trade_no=obj.order_sn,total_amount=obj.order_mount,)re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)return re_urlclass Meta:model = OrderInfofields = "__all__"class OrderSerializer(serializers.ModelSerializer):user = serializers.HiddenField(default=serializers.CurrentUserDefault())pay_status = serializers.CharField(read_only=True)trade_no = serializers.CharField(read_only=True)order_sn = serializers.CharField(read_only=True)pay_time = serializers.DateTimeField(read_only=True)alipay_url = serializers.SerializerMethodField(read_only=True)def get_alipay_url(self, obj):alipay = AliPay(# 填写自己的appid(必填)appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")url = alipay.direct_pay(subject=obj.order_sn,out_trade_no=obj.order_sn,total_amount=obj.order_mount,)re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)return re_urldef generate_order_sn(self):# 当前时间+userid+随机数from random import Randomrandom_ins = Random()order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),userid=self.context["request"].user.id, ranstr=random_ins.randint(10, 99))return order_sndef validate(self, attrs):attrs["order_sn"] = self.generate_order_sn()return attrsclass Meta:model = OrderInfofields = "__all__"

trade文件夹下views.py代码如下:

views.py

import time
from datetime import datetime
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from rest_framework import mixins
from django.shortcuts import redirectfrom .serializers import ShopCartSerializer, OrderDetailSerializer, ShopCartDetailSerializer, OrderSerializer
from utils.permissions import IsOwnerOrReadOnly
from .models import ShoppingCart, OrderInfo, OrderGoodsclass ShoppingCartViewset(viewsets.ModelViewSet):"""购物车功能list:获取购物车详情create:加入购物车delete:删除购物记录"""permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)serializer_class = ShopCartSerializerlookup_field = "goods_id"def perform_create(self, serializer):shop_cart = serializer.save()goods = shop_cart.goodsgoods.goods_num -= shop_cart.numsgoods.save()def perform_destroy(self, instance):goods = instance.goodsgoods.goods_num += instance.numsgoods.save()instance.delete()def perform_update(self, serializer):existed_record = ShoppingCart.objects.get(id=serializer.instance.id)existed_nums = existed_record.numssaved_record = serializer.save()nums = saved_record.nums - existed_numsgoods = saved_record.goodsgoods.goods_num -= numsgoods.save()def get_serializer_class(self):if self.action == 'list':return ShopCartDetailSerializerelse:return ShopCartSerializerdef get_queryset(self):return ShoppingCart.objects.filter(user=self.request.user)class OrderViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin,viewsets.GenericViewSet):"""订单管理list:获取个人订单delete:删除订单create:新增订单"""permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)serializer_class = OrderSerializerdef get_queryset(self):return OrderInfo.objects.filter(user=self.request.user)def get_serializer_class(self):if self.action == "retrieve":return OrderDetailSerializerreturn OrderSerializerdef perform_create(self, serializer):order = serializer.save()shop_carts = ShoppingCart.objects.filter(user=self.request.user)for shop_cart in shop_carts:order_goods = OrderGoods()order_goods.goods = shop_cart.goodsorder_goods.goods_num = shop_cart.numsorder_goods.order = orderorder_goods.save()shop_cart.delete()return orderfrom rest_framework.views import APIView
from utils.alipay import AliPay
from Mxshop.settings import ali_pub_key_path, private_key_path
from rest_framework.response import Responseclass AlipayView(APIView):def get(self, request):"""处理支付宝的return_url返回:param request::return:"""processed_dict = {}for key, value in request.GET.items():processed_dict[key] = valuesign = processed_dict.pop("sign", None)alipay = AliPay(# 填写自己的appid(必填)appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")verify_re = alipay.verify(processed_dict, sign)if verify_re is True:order_sn = processed_dict.get('out_trade_no', None)trade_no = processed_dict.get('trade_no', None)trade_status = processed_dict.get('trade_status', None)existed_orders = OrderInfo.objects.filter(order_sn=order_sn)for existed_order in existed_orders:existed_order.pay_status = trade_statusexisted_order.trade_no = trade_noexisted_order.pay_time = datetime.now()existed_order.save()response = redirect("index")response.set_cookie("nextPath", "pay", max_age=3)return responseelse:response = redirect("index")return responsedef post(self, request):"""处理支付宝的notify_url:param request::return:"""processed_dict = {}for key, value in request.POST.items():processed_dict[key] = valuesign = processed_dict.pop("sign", None)alipay = AliPay(# 填写自己的appid(必填)appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")verify_re = alipay.verify(processed_dict, sign)if verify_re is True:order_sn = processed_dict.get('out_trade_no', None)trade_no = processed_dict.get('trade_no', None)trade_status = processed_dict.get('trade_status', None)existed_orders = OrderInfo.objects.filter(order_sn=order_sn)for existed_order in existed_orders:order_goods = existed_order.goods.all()for order_good in order_goods:goods = order_good.goodsgoods.sold_num += order_good.goods_numgoods.save()existed_order.pay_status = trade_statusexisted_order.trade_no = trade_noexisted_order.pay_time = datetime.now()existed_order.save()return Response("success")

utils文件夹下alipay.py代码如下:

alipay.py


# pip install pycryptodomefrom datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytesimport jsonclass AliPay(object):"""支付宝支付接口"""def __init__(self, appid, app_notify_url, app_private_key_path,alipay_public_key_path, return_url, debug=False):self.appid = appidself.app_notify_url = app_notify_urlself.app_private_key_path = app_private_key_pathself.app_private_key = Noneself.return_url = return_urlwith open(self.app_private_key_path) as fp:self.app_private_key = RSA.importKey(fp.read())self.alipay_public_key_path = alipay_public_key_pathwith open(self.alipay_public_key_path) as fp:self.alipay_public_key = RSA.import_key(fp.read())if debug is True:self.__gateway = "https://openapi.alipaydev.com/gateway.do"else:self.__gateway = "https://openapi.alipay.com/gateway.do"def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):biz_content = {"subject": subject,"out_trade_no": out_trade_no,"total_amount": total_amount,"product_code": "FAST_INSTANT_TRADE_PAY",# "qr_pay_mode":4}biz_content.update(kwargs)data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)return self.sign_data(data)def build_body(self, method, biz_content, return_url=None):data = {"app_id": self.appid,"method": method,"charset": "utf-8","sign_type": "RSA2","timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),"version": "1.0","biz_content": biz_content}if return_url is not None:data["notify_url"] = self.app_notify_urldata["return_url"] = self.return_urlreturn datadef sign_data(self, data):data.pop("sign", None)# 排序后的字符串unsigned_items = self.ordered_data(data)unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)sign = self.sign(unsigned_string.encode("utf-8"))# ordered_items = self.ordered_data(data)quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)# 获得最终的订单信息字符串signed_string = quoted_string + "&sign=" + quote_plus(sign)return signed_stringdef ordered_data(self, data):complex_keys = []for key, value in data.items():if isinstance(value, dict):complex_keys.append(key)# 将字典类型的数据dump出来for key in complex_keys:data[key] = json.dumps(data[key], separators=(',', ':'))return sorted([(k, v) for k, v in data.items()])def sign(self, unsigned_string):# 开始计算签名key = self.app_private_keysigner = PKCS1_v1_5.new(key)signature = signer.sign(SHA256.new(unsigned_string))# base64 编码,转换为unicode表示并移除回车sign = encodebytes(signature).decode("utf8").replace("\n", "")return signdef _verify(self, raw_content, signature):# 开始计算签名key = self.alipay_public_keysigner = PKCS1_v1_5.new(key)digest = SHA256.new()digest.update(raw_content.encode("utf8"))if signer.verify(digest, decodebytes(signature.encode("utf8"))):return Truereturn Falsedef verify(self, data, signature):if "sign_type" in data:sign_type = data.pop("sign_type")# 排序后的字符串unsigned_items = self.ordered_data(data)message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)return self._verify(message, signature)if __name__ == "__main__":return_url = 'http://127.0.0.1:8000/?total_amount=100.00&timestamp=2020-04-24+23%3A53%3A34&sign=e9E9UE0AxR84NK8TP1CicX6aZL8VQj68ylugWGHnM79zA7BKTIuxxkf%2FvhdDYz4XOLzNf9pTJxTDt8tTAAx%2FfUAJln4WAeZbacf1Gp4IzodcqU%2FsIc4z93xlfIZ7OLBoWW0kpKQ8AdOxrWBMXZck%2F1cffy4Ya2dWOYM6Pcdpd94CLNRPlH6kFsMCJCbhqvyJTflxdpVQ9kpH%2B%2Fhpqrqvm678vLwM%2B29LgqsLq0lojFWLe5ZGS1iFBdKiQI6wZiisBff%2BdAKT9Wcao3XeBUGigzUmVyEoVIcWJBH0Q8KTwz6IRC0S74FtfDWTafplUHlL%2Fnf6j%2FQd1y6Wcr2A5Kl6BQ%3D%3D&trade_no=2017081521001004340200204115&sign_type=RSA2&auth_app_id=2016080600180695&charset=utf-8&seller_id=2088102170208070&method=alipay.trade.page.pay.return&app_id=2016080600180695&out_trade_no=20170202185&version=1.0'o = urlparse(return_url)query = parse_qs(o.query)processed_query = {}ali_sign = query.pop("sign")[0]alipay = AliPay(# 填写自己的appid(必填)appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path="../trade/keys/private_2048.txt",alipay_public_key_path="../trade/keys/alipay_key_2048.txt",  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")for key, value in query.items():processed_query[key] = value[0]print (alipay.verify(processed_query, ali_sign))url = alipay.direct_pay(subject="测试订单2",out_trade_no="202004241888",total_amount=100,return_url="http://127.0.0.1:8000/alipay/return/")re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)print(re_url)

支付宝windows密钥生成器,linux用户使用自带的openssl进行密钥生成即可。

https://ideservice.alipay.com/ide/getPluginUrl.htm?clientType=assistant&platform=win&channelType=WEB

settings.py

STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),
)
#支付宝相关配置
private_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/private_2048.txt')
ali_pub_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/alipay_key_2048.txt')

url.py

from django.conf.urls import url,include
# from django.contrib import admin
import xadmin
from Mxshop.settings import MEDIA_ROOT
from django.views.static import serve
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken import views
from rest_framework_jwt.views import obtain_jwt_tokenfrom goods.views import GoodsListViewSet,CategoryViewset,HotSearchsViewset
from users.views import SmsCodeViewset,UserViewset
from user_operation.views import UserFavViewset, LeavingMessageViewset, AddressViewset
from trade.views import ShoppingCartViewset, OrderViewsetrouter = DefaultRouter()#配置goods的url
router.register(r'goods', GoodsListViewSet, base_name="goods")#配置category的url
router.register(r'categorys', CategoryViewset, base_name="categorys")router.register(r'codes', SmsCodeViewset, base_name="codes")router.register(r'hotsearchs', HotSearchsViewset, base_name="hotsearchs")router.register(r'users', UserViewset, base_name="users")#收藏
router.register(r'userfavs', UserFavViewset, base_name="userfavs")#留言
router.register(r'messages', LeavingMessageViewset, base_name="messages")#收货地址
router.register(r'address', AddressViewset, base_name="address")#购物车url
router.register(r'shopcarts', ShoppingCartViewset, base_name="shopcarts")#订单相关url
router.register(r'orders', OrderViewset, base_name="orders")goods_list = GoodsListViewSet.as_view({'get': 'list',
})from trade.views import AlipayView
from django.views.generic import TemplateView
urlpatterns = [url(r'^xadmin/', xadmin.site.urls),url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),url(r'^', include(router.urls)),url(r'^index/', TemplateView.as_view(template_name="index.html"), name="index"),url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),url(r'docs/',include_docs_urls(title='GOHB生鲜')),# drf自带的token认证模式url(r'^api-token-auth/', views.obtain_auth_token),# jwt的认证接口url(r'^login/', obtain_jwt_token),url(r'^alipay/return/', AlipayView.as_view(), name="alipay"),
]

如果在windows下,可以下载支付宝开放平台开发助手生成密钥,如果在linux下,采用本地的openssl即可生成(以下均为windows下操作)


将生成的公钥添加到支付宝沙箱环境的公钥中,并保存

复制APPID

将刚刚生成的密钥放在trade文件夹下keys文件夹下private_2048,pub_2048文件中(小编这里是在工具类Alipay.py中这样命名的)

复制支付宝公钥

将其放入alipay_key_2048中


测试是否正常返回沙箱

出现支付宝沙箱开发问题,请更换浏览器查看即可,或者关闭自己的浏览器代理。

正常访问页面,如下:

cnpm run build,生成静态文件放进django的template下

在页面点击支付宝支付

成功跳转支付页面

Django 前后端分离实战项目 生鲜超市(十四)之支付宝接入相关推荐

  1. Django 前后端分离实战项目 生鲜超市(七)之Vue展示商品分类数据和搜索

    Vue展示商品分类数据和搜索 前言 所有vue接口全部在src/api/api.js文件下 代码已上传至github:https://github.com/kalipoison/fresh-marke ...

  2. 视频教程-Angular+Django前后端分离实战项目开发教程-AngularJS

    Angular+Django前后端分离实战项目开发教程 胜蓝博创(韬略课堂)创始人,IT培训讲师,先后在蓝港在线,热酷,乐元素等大型游戏公司任职,参与过多款大型网游.手游的设计和开发,精通页游.手游前 ...

  3. 视频教程-全新Go语言前后端分离实战项目(Beego)-Go语言

    全新Go语言前后端分离实战项目(Beego) 张长志技术全才.擅长领域:区块链.大数据.Java等.10余年软件研发及企业培训经验,曾为多家大型企业提供企业内训如中石化,中国联通,中国移动等知名企业. ...

  4. 前后端分离(VUE+SPRINGBOOT)十四 微信移动端 企业微信的开发1

    因为项目中设计到要调用微信接口,接口如下: 1,获取用户的 code     redirect_uri 做URLENCODE处理 https://open.weixin.qq.com/connect/ ...

  5. 视频教程-Python+Vue+Django前后端分离项目实战-Python

    Python+Vue+Django前后端分离项目实战 教学风格独特,以学员视角出发设计课程,难易适度,重点突出,架构清晰,将实战经验融合到教学中.讲授技术同时传递方法.得到广大学员的高度认可. 王进 ...

  6. Nginx+uwsgi+celery+supervisor部署Django前后端分离项目

    转载 Nginx+uwsgi+celery+supervisor部署Django前后端分离项目 ljmict 0人评论 3887人阅读 2018-08-08 01:29:45 本实验实现了负载均衡.反 ...

  7. 视频教程-SpringBoot2+Vue+AntV前后端分离开发项目实战-Java

    SpringBoot2+Vue+AntV前后端分离开发项目实战 10多年互联网一线实战经验,现就职于大型知名互联网企业,架构师, 有丰富实战经验和企业面试经验:曾就职于某上市培训机构数年,独特的培训思 ...

  8. SpringBoot+Vue前后端分离实战(用户注册登录)

    文章目录 前言 注册 前端部分逻辑 发送请求 后端处理 登录 前端获取token 前端token状态管理 后端处理 用户登录 生成token 拦截器设置 总结 前言 昨天抽空终于把后端架起来了,准备开 ...

  9. Django前后端分离实现登录验证码功能

    Django前后端分离实现登录验证码功能 当下最流行最热门的开发方式当属前后端分离开发,分工也更加明确与专注,前端也是越来越难,几天不学习就跟不上节奏,一个月不学习可以好不夸张的说,你已经不适合这个行 ...

最新文章

  1. buu 大帝的密码武器
  2. SSM+Maven整合时在Eclipse中使用Mybatis逆向工程自动生成代码
  3. HDOJ1874最短路【spfa】
  4. android 获取webView高度,设置webView高度
  5. Linux断点方法,一种基于Linux问题断点的定位方法及系统与流程
  6. 护航敏捷开发和运维 BCS2020举办DevSecOps论坛
  7. Sql中的union和union all的讲解
  8. python 爬虫(一) requests+BeautifulSoup 爬取简单网页代码示例
  9. c语言链表移动北理工,北京理工大学c语言网络教室 链表
  10. 一路PN码串行捕获设计--基于《通信收发信机的verilog实现与仿真》实例
  11. opencv_python Stitcher拼接图像实例(SIFT/SURF检测特征点,BF/FLANN匹配特征点)
  12. 工作效率低,怎么办?
  13. js网页进度条等待特效
  14. 高中关于人工智能方面的课题_AI相关专业或成热门?高中生也可以入门“人工智能”...
  15. 技术杂谈 | 分享Iteye的开涛对IoC的精彩讲解
  16. 数字图像处理第二章——数字图像基础
  17. 编程好学吗?多长时间才能学会?需要注意些什么?
  18. WMS系统的功能,业务和定义
  19. rap2-delos搭建
  20. Django视图学习——处理Http404异常

热门文章

  1. 如何实现内网会议直播与内网培训直播
  2. Java Swing 主题(LF)推荐 - FlatLaf
  3. iframe iframe参数
  4. slam 基础之机器人学中的坐标转换学习总结
  5. infinity mysql,SQLException: 'Infinity' is not a valid numeric or
  6. 计算机组成原理:二进制编码
  7. 论文投稿指南——中文核心期刊推荐(综合性经济科学)
  8. 深度学习(自然语言处理)Seq2Seq学习笔记(采用GRU且进行信息压缩)(二)
  9. 第一学期考试 计算机科学导论,计算机科学导论试题-2013
  10. Puzzle Pieces