【附Demo】Django 对接支付宝电脑网站、手机网站、App支付步骤详解

34 篇文章 3 订阅

一、前言

本文主要针对 Python for Django 在对接支付宝电脑网站、手机网站、App支付过程中具体实现步骤进行详解;

相信大家支付功能也写了不少,但时间一长,再次用到的时候有些细节难免会忘记,此篇文章就为方便后续快速实现支付宝各支付功能集成而作。

支付Demo源码地址详见:《Alipay_demo》 下载即可使用

关联文章 《30分钟未支付自动取消订单的设计方案》 将在下一篇分享~~

好文章 记得收藏+点赞+关注额 !!!

---- Nick.Peng


二、支付宝开发者相关文档

  • 支付宝开发文档: https://openhome.alipay.com/developmentDocument.htm
  • 支付快速接入文档: https://docs.open.alipay.com/270/105899/
  • 官方SDK地址: https://docs.open.alipay.com/270/106291/
  • 非官方支付宝SDK地址: https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
  • 开发帮助中心: https://opensupport.alipay.com/support/helpcenter/192
    对接过程中如果遇到难题,可以在帮助中心寻找答案

三、各支付功能支付流程图

  • 支付流程文字叙述如下,以电脑网站支付为例
  • 用户点击下单,生成订单信息,前端携带后端生成返回的订单id,调取获取支付宝支付链接口,接口返回支付链接(包含订单编号,总金额,return_url,notify_url 等参数);
  • 前端获取到支付宝支付链接后,构建form表单,向支付宝服务器发起支付请求;
  • 进入支付宝支付页面,登录支付宝,登录成功后输入支付密码,进行支付;
  • 支付成功后跳转到支付成功页面,支付宝携带支付结果数据重定向到商户指定的 return_url 页面;
  • 前端携带支付成功结果数据,向同步回调通知接口发起请求,后端验签成功后返回支付成功业务逻辑响应;
  • 同时支付宝服务器也会根据提供的 notify_url 异步请求异步通知接口,后端验签成功,保存支付结果,并返回 success 字符给支付宝服务器;
  • 到此支付流程结束

在这里插入图片描述

四、支付宝接入前准备

4.1 创建应用
  • 安装SDK: pip install python-alipay-sdk==1.7.1
  • 创建项目: django-admin startproject alipay_demo
  • 创建应用: python manage.py startapp payment
  • 本Demo目录结构
    在这里插入图片描述
4.2 配置公私钥

此步主要完成两个配置文件,即:应用私钥:app_private_key.pem,支付宝公钥:alipay_public_key.pem

  • 生成应用的私钥和公钥,Windows用户请下载签名工具

    # 打开终端,输入openssl回车,一次执行以下命令生成应用公私钥
    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  #退出OpenSSL程序
    
  • 保存应用私钥文件
    在 payment 应用中新建 keys 目录,用来保存秘钥文件。
    将应用私钥文件 app_private_key.pem 复制到 payment/keys 目录下, 内容如下。

    -----BEGIN RSA PRIVATE KEY-----
    此处为上面生成的应用私钥
    -----BEGIN RSA PRIVATE KEY-----
    
  • 查看公钥

    cat app_publict_key.pem
    

    将应用公钥内容复制粘贴到支付宝控制台进行配置,会得到支付宝公钥;如图,第一次应该是设置应用公钥
    注意:对应加密方式进行配置,推荐RSA2。
    在这里插入图片描述

  • 保存支付宝公钥
    在 payment/keys 目录下新建 alipay_public_key.pem 文件,用于保存支付宝的公钥文件。
    将上一步生成的支付宝的公钥内容复制到 alipay_public_key.pem 文件中,格式如下:
    在这里插入图片描述
    注意:还需要在公钥文件中补充开始与结束标志,格式如下:

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

五、支付视图接口实现

5.0 封装支付宝支付对象
  • 代码如下: 写到 payment 应用里的 utils.py 工具里

    # -*- coding: utf-8 -*-
    import os
    
    from alipay import AliPay  # python-alipay-sdk
    from django.conf import settings
    
    
    def my_ali_pay(notify_url=None):
        """
        支付宝支付对象
        :param notify_url:
        支付成功支付宝服务器异步通知默认回调url,会向这个地址发送POST请求,接口实现校验是否支付已经完成,注意:此地址需要能在公网进行访问
        :return: 支付对象
        """
        ali_pay_obj = AliPay(
            appid=settings.ALI_PAY_APP_ID,
            app_notify_url=notify_url,  # 支付成功支付宝服务器异步通知默认回调url, 即会向这个地址发送POST请求
            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",  # RSA 或者 RSA2
            debug=settings.ALI_PAY_DEBUG  # 是否是沙箱环境, 默认False
        )
    
        return ali_pay_obj
        
    
5.1 获取支付链接接口实现
  • 代码如下: 以下为视图,写在 payment 应用的 views.py 文件里

    import random
    
    from urllib import parse
    from django.conf import settings
    from django.db.transaction import atomic
    from django.http import JsonResponse, HttpResponse
    from django.utils import timezone
    from django.views.decorators.csrf import csrf_exempt
    
    from apps.payment.utils import my_ali_pay, is_app_pay
    from utils.common import get_domain
    
    
    @csrf_exempt
    def get_pay_url(request):
        """
        获取支付宝支付链接
        :return: 支付链接ali_pay_url
        """
        if request.method == "GET":
            order_id = request.GET.get('order_id', 0)  # 前端传回的订单id
            money = request.GET.get('price')  # 前端传回的金额数据
    
            if not all([order_id, money]):
                return JsonResponse(dict(message="参数错误"))
    
            # 此处可增加根据订单id查询判断该订单是否存在相关业务逻辑
    
            # 组织订单编号:当前时间字符串 + 6位随机数 ---> 20200808154711123456
            out_trade_no = timezone.now().strftime('%Y%m%d%H%M%S') + ''.join(map(str, random.sample(range(0, 9), 6)))
    
            # 生成支付宝支付链接地址
            domain_name = get_domain(request)
            notify_url = domain_name + '/payment/update_order/'
            ali_pay = my_ali_pay(notify_url)
            order_string = ali_pay.api_alipay_trade_page_pay(
                out_trade_no=out_trade_no,  # 订单编号
                total_amount=str(money),  # 交易金额(单位: 元 保留俩位小数)   这里一般是从前端传过来的数据
                subject=f"产品名称-{out_trade_no}",  # 商品名称或产品名称
                return_url=domain_name + "/payment/get_result/",  # 支付成功后跳转的页面,App支付此参数无效,集成支付宝SDK自带跳转
            )
            # 拼接支付链接,注意:App支付不需要返回支付宝网关
            ali_pay_url = order_string if is_app_pay(order_string) else settings.ALI_PAY_URL + "?" + order_string
    
            return JsonResponse(dict(ali_pay_url=ali_pay_url))
    
        return JsonResponse(dict(ali_pay_url=""))
        
    
5.2 支付成功同步回调通知接口实现
  • 代码如下:

    @csrf_exempt
    def pay_result(request):
        """
        前端同步回调通知(支付完成后,前端url会接收支付宝支付完成后回传的form参数,将其全部传给该接口进行验签),参数示例如下:
        ?charset=utf-8&out_trade_no=20200808154711123456&method=alipay.trade.page.pay.return&total_amount=0.01&sign=FtDkDtsDE9dW3RB18BfiAeFqkSQAK......E1wE9tgsoUi50%2B0IH7w%3D%3D&trade_no=2020080622001460481436975535&auth_app_id=2016101000655892&version=1.0&app_id=2016101000655892&sign_type=RSA2&seller_id=2087811328364696&timestamp=2020-08-06+12%3A44%3A44
        :return: 根据业务需求自定义返回信息
        """
        if request.method == "GET":
            data = request.GET.dict()
    
            ali_pay = my_ali_pay()
            sign = data.pop('sign', None)
            success = ali_pay.verify(data, sign)
            print("同步回调验签状态: ", success)
            if success:
                # 此处写支付验签成功的相关业务逻辑
                return JsonResponse(dict(message="支付成功"))
    
            return JsonResponse(dict(message="支付失败"))
    
        return JsonResponse(dict(message="支付失败"))
        
    
5.3 支付成功异步通知接口实现
  • 代码如下:

    @csrf_exempt
    @atomic()
    def update_order(request):
        """
        支付成功后,支付宝服务器异步通知回调(用于修改订单状态)
        :return: success or fail
        """
        if request.method == "POST":
    
            body_str = request.body.decode('utf-8')
            data = parse.parse_qs(body_str)
            # data = parse.parse_qs(parse.unquote(body))  # 前端回传的url如果被编码,这里需要用unquote解码再转换成字典
            data = {k: v[0] for k, v in data.items()}
    
            ali_pay = my_ali_pay()
            sign = data.pop('sign', None)
            success = ali_pay.verify(data, sign)  # 返回验签结果, True/False
            print("异步通知验证状态: ", success)
            if success:
                # 此处写支付验签成功修改订单状态相关业务逻辑
                return HttpResponse('success')  # 返回success给支付宝服务器, 若支付宝收不到success字符会重复发送通知
            return HttpResponse('fail')
    
        return HttpResponse('fail')
        
    

六、区别总结

在这里插入图片描述

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值