python使用第三方支付宝SDK实现小程序发红包、用户支付等功能

python使用第三方支付宝SDK实现小程序发红包、用户支付等功能

  • 实现小程序发红包,创建支付订单、登录验证等
    • 继承DCAlipay添加几个我们需要的功能
    • 初始化DCAlipay对象并使用
    • 回调notify_url

支付宝官方SDK是相当的难用,而且python官方SDK不支持验签,验签功能需要自己写,因此使用了第三方SDK:python-alipay-sdk
地址:github连接
验签步骤:支付宝平台官方说明
如果需要自己实现验签:验签实现逻辑

首先安装:

pip install python-alipay-sdk --upgrade

实现小程序发红包,创建支付订单、登录验证等

第三方SDK实际上已经实现了验签逻辑,但是功能比较少,我们需要的发红包、小程序创建支付订单、登录逻辑之类的都没有,因此我们自己来扩展一下

首先在官方的验签步骤页我们应该生成了自己的密钥文件,大概是这样:

  • 这里每个文件夹代表一个小程序
  • 前四个文件分别对应需要的密钥文件

python使用第三方支付宝SDK实现小程序发红包、用户支付等功能_第1张图片
先看下demo创建一个支付宝web订单,之后模仿源码添加我们需要的功能即可:

from alipay import AliPay, DCAlipay

dc_alipay = DCAliPay(
    appid="appid",
    app_notify_url="http://example.com/app_notify_url",
    app_private_key_string=app_private_key_string,
    app_public_key_cert_string=app_public_key_cert_string,
    alipay_public_key_cert_string=alipay_public_key_cert_string,
    alipay_root_cert_string=alipay_root_cert_string
)
subject = "测试订单"

# Pay via Web,open this url in your browser: https://openapi.alipay.com/gateway.do? + order_string
order_string = dc_alipay.api_alipay_trade_page_pay    (
    out_trade_no="20161112",
    total_amount=0.01,
    subject=subject,
    return_url="https://example.com",
    notify_url="https://example.com/notify" # this is optional
)

继承DCAlipay添加几个我们需要的功能

  • 这里只使用新的验签方式,即要四个证书文件,以往使用的公钥和私钥不再使用了
  • SDK里有个坑,如果不是他设定好的method将不会添加回调url,因此我们自己加上
  • 同样的,登录需要的参数我们也自己添加
from alipay import DCAliPay
from alipay import compat


class CBAliPay(DCAliPay):
    def api_alipay_fund_trans_uni_transfer(self, out_biz_no, trans_amount, payee_info, biz_scene=None,
                                           product_code=None, **kwargs):
        """ 商家转账给用户即发红包 """                                
        if not product_code:
            product_code = "STD_RED_PACKET"
        if not biz_scene:
            biz_scene = "DIRECT_TRANSFER"
        biz_content = {
            "out_biz_no": out_biz_no,
            "trans_amount": trans_amount,
            "payee_info": payee_info,
            "product_code": product_code,
            "biz_scene": biz_scene
        }
        print(biz_content)
        biz_content.update(**kwargs)

        data = self.build_body("alipay.fund.trans.uni.transfer", biz_content)

        url = self._gateway + "?" + self.sign_data(data)
        raw_string = compat.urlopen(url, timeout=15).read().decode("utf-8")
        return self._verify_and_return_sync_response(raw_string, "alipay_fund_trans_uni_transfer_response")

    def api_alipay_trade_create(self, out_trade_no, total_amount, subject, buyer_id, notify_url, **kwargs):
        """ 小程序创建订单,返回out_trade_no给前端即可 """
        biz_content = {
            "out_trade_no": out_trade_no,
            "total_amount": total_amount,
            "subject": subject,
            "buyer_id": buyer_id,
        }
        print(biz_content)
        biz_content.update(**kwargs)

        data = self.build_body("alipay.trade.create", biz_content)
        # SDK里有个坑,如果不是他设定好的method将不会添加回调url,因此我们自己加上
        data['notify_url'] = notify_url

        url = self._gateway + "?" + self.sign_data(data)
        raw_string = compat.urlopen(url, timeout=15).read().decode("utf-8")
        return self._verify_and_return_sync_response(raw_string, "alipay_trade_create")

    def api_alipay_system_oauth_token(self, grant_type="authorization_code", code='', **kwargs):
        """ 登录验签 """
        data = self.build_body("alipay.system.oauth.token", {})
        # 登录需要的参数我们也自己添加
        data['grant_type'] = grant_type
        data['code'] = code

        url = self._gateway + "?" + self.sign_data(data)
        raw_string = compat.urlopen(url, timeout=15).read().decode("utf-8")
        return self._verify_and_return_sync_response(raw_string, "alipay_system_oauth_token")

    def api_alipay_user_info_share(self, auth_token, **kwargs):
		""" 获取用户信息 """ 
        data = self.build_body("alipay.user.info.share", {})
        data['auth_token'] = auth_token
        print(data)
        url = self._gateway + "?" + self.sign_data(data)
        raw_string = compat.urlopen(url, timeout=15).read().decode("utf-8")
        return self._verify_and_return_sync_response(raw_string, "alipay_user_info_share")

初始化DCAlipay对象并使用

  • 代码有所简化,直接使用可能会有问题
  • 初始化时添加了默认回调url,在具体使用时可以更换需要的回调url
  • 回调url地址我都放在了flask app的配置文件里
from util.CBAlipay import CBAliPay


def getCBAlipay(app_id):
	""" 初始化对象 """
    app_private_key_string = open("./cert/{}/app_private.pem".format(appid)).read()
    # app_public_key_cert_string = open("./cert/{}/caibo-inc.com_public.pem".format(appid)).read()
    app_public_key_cert_string = open("./cert/{}/app_public.crt".format(appid)).read()
    alipay_public_key_cert_string = open("./cert/{}/alipayCertPublicKey_RSA2.crt".format(appid)).read()
    alipay_root_cert_string = open("./cert/{}/alipayRootCert.crt".format(appid)).read()

    dc_alipay = CBAliPay(
        appid=appid,
        # 默认回调url
        app_notify_url=current_app.config['ALIPAY_NOTIFY_URL'],
        app_private_key_string=app_private_key_string,
        app_public_key_cert_string=app_public_key_cert_string,
        alipay_public_key_cert_string=alipay_public_key_cert_string,
        alipay_root_cert_string=alipay_root_cert_string,
        sign_type="RSA2"
    )
    return dc_alipay


def transferRequest(app_id, alipay_user_id, amount):
    """ 发红包 """
    dc_alipay = getCBAlipay(app_id)
    if not dc_alipay:
        return False

    payee_info = {"identity_type": "ALIPAY_USER_ID", "identity": alipay_user_id}
    result = dc_alipay.api_alipay_fund_trans_uni_transfer(out_biz_no=datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
                                                          trans_amount=amount, payee_info=payee_info)
    print(result)
    return result


def alipayOrder(app_id, subject, out_trade_no, buyer_id, total_amount, notify_url):
    """ 付款 """
    dc_alipay = getCBAlipay(app_id)
    if not dc_alipay:
        return False
    result = dc_alipay.api_alipay_trade_create(subject=subject, out_trade_no=out_trade_no,
                                               total_amount=total_amount, buyer_id=buyer_id,
                                               notify_url=notify_url)
    print(result)
    return result


def systemOAuthToken(code="", app_id="", grant_type="authorization_code"):
    """ 用户登录 """
    dc_alipay = getCBAlipay(app_id)
    if not dc_alipay:
        return False
    result = dc_alipay.api_alipay_system_oauth_token(grant_type=grant_type,
                                                     code=code)
    print(result)
    return result

回调notify_url

# coding=utf-8
import time
from flask import current_app, request
from . import home
from util import UserFinanceUtil, AlipayUtil


@home.route('/alipay/notify_url', methods=['GET', 'POST'])
def notify():
    """ 支付回调 """
    print(request.form.to_dict())
    data = request.form.to_dict()
    if data is None or data == "":
        return "error: empty data"
    signature = data.pop("sign")
    res = 'success'
    # 根据订单号动态配置
    out_trade_no = data.get('out_trade_no')
    # 这里从数据库获取信息,判断是哪个小程序
    app_id = ...  # 省略
    alipay = AlipayUtil.getCBAlipay(app_id)
    # verify
    success = alipay.verify(data, signature)
    print(success)
    if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
        print("trade succeed")
        # 这里已经验签成功了,执行自己需要的操作即可
        ...
    else:
        res = 'false'
    return res

你可能感兴趣的:(Flask)