Django中对接第三方支付(支付宝)实现支付的流程
1. 业务逻辑
准备
1. 使用沙箱提供的商家环境
沙箱环境:是支付宝提供给开发者的模拟支付的环境
沙箱应用:https://docs.open.alipay.com/200/105311
沙箱账号:https://openhome.alipay.com/platform/appDaily.htm?tab=account
支付宝开发者文档:
文档主页:https://openhome.alipay.com/developmentDocument.htm
产品介绍:https://docs.open.alipay.com/270
快速接入:https://docs.open.alipay.com/270/105899/
SDK:https://docs.open.alipay.com/270/106291/
python对接支付宝SDK:https://github.com/fzlee/alipay/blob/master/README.zh-hans.m
API列表:https://docs.open.alipay.com/270/105900/
2.. 生成密钥对
3. 将公钥加到商品环境中
4. 将Alipay提供的公钥加入项目中
支付功能
5. 根据order_id查询订单对象
6. 创建alipay对象
7. 调用方法,生成url
8. 返回url
保存支付状态
9. 根据返回的url请求支付宝
10. 支付成功后返回商家回调页面--------->会传回很多Alipay传回来的参数,很多明文,防止别人攻击
11. 返回商家的同时请求后台服务器------>发送这些参数给后台
12. 接收参数并且验证,成功则创建订单支付对象返回订单号,否则提示支付失败
2.安装包
pip install python-alipay-sdk --upgrade
3.新建一个payments的app应用
python ../../manage.py startapp payments
4.定义一个模型类,继承自BaseModel(创建时间与修改时间)
class Payment(BaseModel): """ 支付信息 """ order = models.ForeignKey( OrderInfo, on_delete=models.CASCADE, verbose_name='订单') trade_id = models.CharField( max_length=100, verbose_name="支付流水号") class Meta: db_table = 'tb_payment' verbose_name = '支付信息' verbose_name_plural = verbose_name
5.配置密钥
5.1.登录沙箱
在payments应用中新建keys目录,用来保存秘钥文件。
将应用私钥文件app_private_key.pem复制到payment/keys目录下。
5.1.1生成应用的私钥和公钥
openssl OpenSSL> genrsa -out app_private_key.pem 2048 # 私钥RSA2 OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem # 导出公钥 OpenSSL> exit
5.2 保存应用私钥文件
5.3 查看公钥
cat app_publict_key.pem
# 将公钥内容复制给支付宝沙箱的<应用私钥>,得到支付宝的<支付宝公钥>
5.4 保存支付宝公钥
在payments/keys目录下新建alipay_public_key.pem文件,用于保存支付宝的公钥文件。
将支付宝的公钥内容复制到alipay_public_key.pem文件中
6.配置路由
GET /orders/(?P<order_id>\d+)/payment/
7.在配置文件中配置ailipay的信息
# 支付宝支付的配置 ALIPAY_APPID = 'xxxxxxxxxxxxx' ALIPAY_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'apps/payments/alipay/app_private_key.pem') ALIPAY_PUBLIC_KEY_PATH = os.path.join(BASE_DIR, 'apps/payments/alipay/alipay_public_key.pem') ALIPAY_DEBUG = True ALIPAY_SUBJECT = '智学客-订单支付' ALIPAY_RETURN_URL = 'http://www.xxx.com/pay_success.html' ALIPAY_GATE = 'https://openapi.alipaydev.com/gateway.do?'
8.定义视图
两个参数:
order_id: 订单编号
alipay_uel: 支付宝支付链接
代码如下:
class AliPayURLView(APIView): def get(self, request, order_id): # 1.根据order_id查询订单对象 try: order_obj = OrderInfo.objects.get(pk=order_id) except: raise Exception("订单号无效") # 2.创建alipay对象 alipay = AliPay( appid=settings.ALIPAY_APPID, app_notify_url=None, app_private_key_path=settings.ALIPAY_PRIVATE_KEY_PATH, alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH, debug=settings.ALIPAY_DEBUG ) # 3.调用方法,生成url # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string order_string = alipay.api_alipay_trade_page_pay( subject=settings.ALIPAY_SUBJECT, out_trade_no=order_id, # 订单编号 total_amount=str(order_obj.total_amount), # 支付总金额,类型为Decimal(),不支持序列化,需要强转成str return_url=settings.ALIPAY_RETURN_URL # 支付成功后的回调地址 ) # 4.返回url return Response({"alipay_url": settings.ALIPAY_GATE + order_string})
8.1 在payments/urls.py中定义路由规则
url('^orders/(?P<order_id>\d+)/payment/$',views.PaymentView.as_view()),
9.保存支付状态
请求方式:PUT /payment/status/?支付宝参数
参数:trade_id:支付宝流水账号
代码实现:
class OrderStatusView(APIView): """验证用户是否登录成功""" def put(self, request): # 1.接收支付宝返回的数据 data = request.query_params.dict() # 2.验证是否支付成功 # 2.1删除签名,不参与验证 signature = data.pop("sign") # 2.2 创建alipay对象 alipay = AliPay( appid=settings.ALIPAY_APPID, app_notify_url=None, app_private_key_path=settings.ALIPAY_PRIVATE_KEY_PATH, alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH, debug=settings.ALIPAY_DEBUG ) # 2.3 调用verify(字典,签名) success = alipay.verify(data, signature) if success: # 支付成功 ''' { 'total_amount': '11388.00', 支付金额 'auth_app_id': '2016082100304973', 应用编号 'method': 'alipay.trade.page.pay.return', 'trade_no': '2018110722001420410500545016',流水号 'timestamp': '2018-11-07 16:59:20',时间 'app_id': '2016082100304973',应用编号 'out_trade_no': '20181107160224000000001',商城的订单编号 'charset': 'utf-8',编码 'seller_id': '2088102172415825',商家编号 'version': '1.0'版本 } ''' # 1 获取订单号 order_id = data["out_trade_no"] # 2 修改订单状态 try: order_obj = OrderInfo.objects.get(pk=order_id) except: raise Exception("订单号无效") order_obj.status = 2 order_obj.save() # 3.创建订单支付对象 trade_no = data.get('trade_no') # 获取流水号 Payment.objects.create( order_id=order_id, trade_no=trade_no ) # 4.响应 return Response({"trade_id": trade_no}) else: raise Exception("支付失败")
9.1 定义路由规则
url('^payment/status/$',views.PaymentStatusView.as_view()),