支付宝支付流程
# 1、在沙箱环境下实名认证:https://openhome.alipay.com/platform/appDaily.htm?tab=info # 2、电脑网站支付API:https://docs.open.alipay.com/270/105898/ # 3、完成RSA密钥生成:https://docs.open.alipay.com/291/105971 # 4、在开发中心的沙箱应用下设置应用公钥:填入生成的公钥文件中的内容 # 5、Python支付宝开源框架:https://github.com/fzlee/alipay # >: pip install python-alipay-sdk --upgrade # 7、公钥私钥设置 """ # alipay_public_key.pem -----BEGIN PUBLIC KEY----- 支付宝公钥 -----END PUBLIC KEY----- # app_private_key.pem -----BEGIN RSA PRIVATE KEY----- 用户私钥 -----END RSA PRIVATE KEY----- """ # 8、支付宝链接 """ 开发:https://openapi.alipay.com/gateway.do 沙箱:https://openapi.alipaydev.com/gateway.do
实际使用
1.文件结构
libs ├── iPay # aliapy二次封装包 │ ├── __init__.py # 包文件 │ ├── keys # 密钥文件夹 │ │ ├── alipay_public_key.pem # 支付宝公钥 │ │ └── app_private_key.pem # 应用私钥 └── └── settings.py # 应用配置
2.安装模块
pip install python-alipay-sdk --upgrade
3.生成公钥私钥
1.网址下载安装软件:
https://docs.open.alipay.com/291/105971
2.利用 软件生成公钥和私钥
3.将公钥和私钥分别配置到文件中
支付宝公钥:拿上述软件所得的公钥取官网换支付宝公钥在配置
alipay_public_key.pem
-----BEGIN PUBLIC KEY----- 支付宝公钥 -----END PUBLIC KEY-----
应用私钥:直接复制上述软件的私钥即可
app_private_key.pem
-----BEGIN RSA PRIVATE KEY----- 应用私钥 -----END RSA PRIVATE KEY-----
4.setting.py文件配置
import os # 支付宝应用id:公司提供 APP_ID = "2016101600699770" # 默认异步回调的地址,通常设置None就行 APP_NOTIFY_URL = None # 应用私钥文件路径 APP_PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'keys', 'app_private_key.pem') # 支付宝公钥文件路径 ALIPAY_PUBLIC_KEY_PATH = os.path.join(os.path.dirname(__file__), 'keys', 'alipay_public_key.pem') # 签名方式 SIGN_TYPE = 'RSA2' # 是否是测试环境 - 是否是支付宝沙箱 DEBUG = True # 支付连接 DEV_PAY_URL = 'https://openapi.alipaydev.com/gateway.do?' PROD_PAY_URL = 'https://openapi.alipay.com/gateway.do?'
5.__init__.py
from alipay import AliPay from .settings import * # 对外提供支付对象 alipay = AliPay( appid=APP_ID, app_notify_url=APP_NOTIFY_URL, app_private_key_path=APP_PRIVATE_KEY_PATH, alipay_public_key_path=ALIPAY_PUBLIC_KEY_PATH, sign_type=SIGN_TYPE, debug=DEBUG ) # 对外提供的支付链接前缀 pay_url = DEV_PAY_URL if DEBUG else PROD_PAY_URL
6.dev.py:同步和异步回调接口url设置
# 前后台base_url UP_BASE_URL = 'http://127.0.0.1:8080' END_BASE_URL = 'http://127.0.0.1:8000' # alipay回调接口配置 # 上线后必须换成官网地址 # 同步回调的接口(get),前后台分离时一般设置前台页面url RETURN_URL = UP_BASE_URL + '/pay/success' # 异步回调的接口(post),一定设置为后台服务器接口 NOTIFY_URL = END_BASE_URL + '/order/success/'
7.视图中使用
返回支付链接
from django.shortcuts import render # Create your views here. from rest_framework.views import APIView import time from . import models from django.conf import settings # 支付 from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.permissions import IsAuthenticated from utils.response import APIResponse #导入alipay对象和支付链接前缀 from libs.iPay import alipay,pay_url class PayAPIView(APIView): # 登录认证 authentication_classes = [JSONWebTokenAuthentication] # 权限认证 permission_classes = [IsAuthenticated] def post(self,request,*args,**kwargs): # 1)获取前台信息:商品,价格,支付方式 request_data = request.data subject = request_data.get('subject') # 获取总价 total_amount = request_data.get('total_amount') # 获取支付方式 pay_type = request_data.get('pay_type') if not (subject and total_amount and pay_type): return APIResponse(2 , '数据有误') # 2) 订单入库 # 创建订单号 out_trade_no = str(time.time()) # 当前登录用户 user = request.user # 订单入库 try: order = models.Order.objects.create(subject=subject,total_amount=total_amount, pay_type=pay_type,out_trade_no=out_trade_no,user=user) except: return APIResponse(1,'订单生成失败') # 生成支付宝链接并返回 order_string = alipay.api_alipay_trade_page_pay( # 订单号 out_trade_no=out_trade_no, # 价格 total_amount=total_amount, # 商品 subject=subject,
#同步回调地址 return_url=settings.RETURN_URL,
#异步回调地址 notify_url=settings.NOTIFY_URL )
# 拼接支付链接 order_url = pay_url + order_string return APIResponse(order_url=order_url
异步回调
# 支付成功的回调不需要登录认证(支付宝回调不会携带token) from . import models #导入模型层 from utils.logging import logger #日志 from rest_framework.response import Response #响应模块 class SuccessAPIView(APIView): # 不能认证,别人支付宝异步回调就进不来了 # authentication_classes = [authentications.JWTAuthentication] # permission_classes = [IsAuthenticated] # 同步回调:前端发送的请求 def patch(self, request, *args, **kwargs): # 将拼接数据转成字典:默认是QueryDict类型,不能使用pop方法 request_data = request.query_params.dict() # 必须将 sign、sign_type(内部有安全处理) 从数据中取出,拿sign与剩下的数据进行校验 sign = request_data.pop('sign') result = alipay.verify(request_data, sign) if result: # 同步回调:修改订单状态 try: out_trade_no = request_data.get('out_trade_no') order = models.Order.objects.get(out_trade_no=out_trade_no) if order.order_status != 1: order.order_status = 1 order.save() except: pass return APIResponse(0, '支付成功') return APIResponse(1, '支付失败') # 支付宝异步回调 def post(self, request, *args, **kwargs): # 默认是QueryDict类型,不能使用pop方法 request_data = request.data.dict() # 必须将 sign、sign_type(内部有安全处理) 从数据中取出,拿sign与剩下的数据进行校验 sign = request_data.pop('sign') result = alipay.verify(request_data, sign) # 异步回调:修改订单状态 if result and request_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED" ): out_trade_no = request_data.get('out_trade_no') logger.critical('%s支付成功' % out_trade_no) try: order = models.Order.objects.get(out_trade_no=out_trade_no) if order.order_status != 1: order.order_status = 1 order.save() except: pass # 支付宝八次异步通知,订单成功一定要返回 success return Response('success') return Response('failed')