Django中实现支付宝支付

匿名 (未验证) 提交于 2019-12-02 23:03:14

接入支付宝支付逻辑

支付流程:

return_url:用户支付成功返回的页面

notify_url:通知商户用户支付成功与否的页面

1-用户点击支付,调用支付宝登录的接口(携带订单编号,总金额,return_url,notify_url参数),获取到支付宝登录的url参数,拼接到支付宝支付的url中

2-登录支付宝,登录成功后输入支付密码

3-支付,支付成功后跳转到支付成功页面

4-支付宝携带支付结果数据重定向到商户指定的return_url页面,显示订单支付成功

5-浏览器携带支付结果数据访问notify_url页面,后端保存支付结果

对称/非对称加密

对称:公钥和私钥的加密方法一样

非对称:公钥和私钥的加密方法不一样

商户和支付宝互相存储对方的公钥,双方发送消息给对方时用各自的私钥验证身份是否合法

支付宝接入

  1. 创建应用
  2. 配置密钥
  3. 搭建和配置开发环境
  4. 接口调用

创建数据库模型类
创建应用payment

from django.db import models  from meiduo_mall.utils.models import BaseModel from orders.models import OrderInfo      class Payment(BaseModel):         """         支付信息         """         order = models.ForeignKey(OrderInfo, on_delete=models.CASCADE, verbose_name='订单')         trade_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="支付编号")              class Meta:             db_table = 'tb_payment'             verbose_name = '支付信息'             verbose_name_plural = verbose_name 

python对接支付宝SDK安装

pip install python-alipay-sdk --upgrade` 

配置秘钥

①生成应用的私钥和公钥

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 

②保存应用私钥文件

在payment应用中新建keys目录,用来保存秘钥文件。

将应用私钥文件app_private_key.pem复制到payment/keys目录下。

③ 查看公钥

cat app_publict_key.pem 

将公钥内容复制给支付宝

④保存支付宝公钥

在payment/keys目录下新建alipay_public_key.pem文件,用于保存支付宝的公钥文件。

将支付宝的公钥内容复制到alipay_public_key.pem文件中

注意,还需要在公钥文件中补充开始与结束标志

-----BEGIN PUBLIC KEY----- 此处是公钥内容 -----END PUBLIC KEY----- 

发起支付的接口

接口设计

1-请求方式:GET /orders/?P<order_id>\d+/payment/

2-请求参数:路径参数order_id

3-返回参数:支付宝支付的url

具体实现

1-校验order_id

2-调用sdk中api获取支付参数

3-将支付参数拼接到支付宝的url

4-返回

# 发起支付接口,获取支付宝支付的url # GET /orders/(?P<order_id>\d+)/payment/ class PayMentView(APIView):     permission_classes = [IsAuthenticated]  # 仅登陆认证的用户才能访问      def get(self, request, order_id):         # 校验订单是否存在         try:             order = OrderInfo.objects.get(                 order_id=order_id,  # 订单编号                 user=request.user,  # 当前用户                 pay_ment=OrderInfo.PAY_METHODS_ENUM['ALIPAY'],  # 支付宝支付                 status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']  # 待支付             )         except OrderInfo.DoesNotExist:             return Response({'message': '订单信息有误'}, status=status.HTTP_400_BAD_REQUEST)          # 向支付宝发起请求,获取支付链接参数         # 通过sdk中的api(AliPay)构造一个支付对象         alipay_client = AliPay(             appid=settings.ALIPAY_APPID,             app_notify_url=None,  # 默认回调url             # 私钥  路径方式指定             app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),                                               "keys/app_private_key.pem"),             # 支付宝公钥  路径方式指定             alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),                                                 "keys/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,             sign_type="RSA2",  # RSA 或者 RSA2             debug=settings.ALIPAY_DEBUG  # 默认False  是否是沙箱环境         )          # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string         # 支付对象调用sdk中的api(api_alipay_trade_page_pay)构造支付链接参数         order_string = alipay_client.api_alipay_trade_page_pay(             out_trade_no=order_id,  # 订单编号             total_amount=str(order.total_amount),  # 总金额             subject='美多商城订单%s' % order_id,             return_url="http://www.meiduo.site:8080/pay_success.html",  # 支付成功之后返回的页面             notify_url=None  # 可选, 不填则使用默认notify url  支付成功与否告诉商户的页面         )          # 拼接支付链接网址         alipay_url = settings.ALIPAY_URL + '?' + order_string          # 返回         return Response({'alipay_url': alipay_url}) 

在配置文件中编辑支付宝的配置信息

# 支付宝  沙箱环境配置 ALIPAY_APPID = "2016081600258081" ALIPAY_URL = "https://openapi.alipaydev.com/gateway.do" ALIPAY_DEBUG = True 

保存支付结果的接口

接口设计

1-请求方式: PUT /payment/status/?支付宝参数

2-请求参数:查询字符串参数,支付宝返回的

3-返回的参数:支付凭证 trade_id

具体实现

接收参数,校验

保存支付结果

修改订单状态

# 支付结果保存 # PUT /payment/status/?支付宝参数 # charset=utf-8 # &out_trade_no=20180704082900000000001 # &method=alipay.trade.page.pay.return # &total_amount=3788.00 # &trade_no=2018070421001004630200569950 # &auth_app_id=2016081600258081 # &version=1.0&app_id=2016081600258081&sign_type=RSA2&seller_id=2088102171419163&timestamp=2018-07-04+16%3A31%3A49  # &sign=UNn3nCckqp4E3MJAonwiywZBtP5Wiia6eJVUta0iimZeLdUuMhH%2FdyRmPGgaQ6xHn0u5KCQbeof4dsXyh%2FdG42cLho9LYCcRqwa6qv3BbEx1J3Y9Qxp6ye%2BTmQq9UbW3%2FoXdAjVJ0gChPQNjm%2BCMI0XbLPT9ARyclb3oKMHrNB7kixMma8OIQbztylSbIwnQilQlxhIWzDqhxCXRgAXjRir7748YpkzW%2FlpkTyuxU1mKI4VwvxV8Of4PQqZcLU%2BbXo2SI%2Bm0Vy%2FgMae4hZIRf%2BbTI1C8lw203HpOMDDeZiUea3GpF9WzuZkTPc4Ryv%2F8K3F6e2IvInpeQt48nqNC%2BQ%3D%3D class PaymentStatusView(APIView):      def put(self, request):         # 接收参数         # 校验         alipay_req_data = request.query_params  # QueryDict         if not alipay_req_data:             return Response({'message': "缺少参数"}, status=status.HTTP_400_BAD_REQUEST)          alipay_req_dict = alipay_req_data.dict()  # 将传过来的支付宝参数转为普通字典         sign = alipay_req_dict.pop('sign')  # 取出传过来的公钥          alipay_client = AliPay(             appid=settings.ALIPAY_APPID,             app_notify_url=None,  # 默认回调url             app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),             alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),                                                 "keys/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,             sign_type="RSA2",  # RSA 或者 RSA2             debug=settings.ALIPAY_DEBUG  # 默认False  是否是沙箱环境         )          # 通过本身的私钥验证传过来的公钥,看是否匹配         # 返回验证结果,True False         result = alipay_client.verify(alipay_req_dict, sign)          if result:  # 如果为True,修改订单状态为待发货,保存支付结果             order_id = alipay_req_dict.get('out_trade_no')             trade_id = alipay_req_dict.get('trade_no')             # 保存支付结果数据Payment             Payment.objects.create(                 order_id=order_id,                 trade_id=trade_id             )             # 修改订单状态为待发货             OrderInfo.objects.filter(order_id=order_id).update(status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'])             return Response({'trade_id': trade_id})         else:             return Response({'message': '参数有误'}, status=status.HTTP_400_BAD_REQUEST) 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!