一、 接入准备
支付宝支付流程没有微信那么复杂,而且支付宝支持沙箱。登录支付宝开放平台控制台
点击开发工具中的沙箱
接口加密方式,我这里使用的是自定义密钥。生成密钥的方式
- 使用支付宝官方提供的密钥工具,唯一要注意的是支付宝密钥工具生成的是 txt 格式的,也就是不包含头部和尾部标识的
-----BEGIN PUBLIC KEY----- -----END PUBLIC KEY-----
- 使用
openssl
命令自己生成。openssl OpenSSL> genrsa -out app_private_key.pem 2048 # 私钥 OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem # 导出公钥 OpenSSL> exit
我们需要的东西基本都有了。调试的使用可以下载工具支付宝客户端沙箱版
,用沙箱账号进行支付。
开发
import logging
from enum import Enum
from Cryptodome.PublicKey import RSA
from alipay import AliPay, AliPayConfig
"""
支付宝支付接入
SDK 文档:https://gitee.com/yqmc/alipay/blob/master/README.zh-hans.md
pip install python-alipay-sdk --upgrade
"""
class AlipayType(Enum):
WEB = 'web' # 电脑网站支付
WAP = 'wap' # 手机网站支付
APP = 'app' # app支付
MINI = 'mini' # 小程序支付
class AliPayClient:
def __init__(self, appid, app_private_key_path, alipay_public_key_path, is_sandbox=False, default_notify_url=None,
return_url=None):
"""
初始化数据
:param appid: APP ID
:param app_private_key_path: 应用私钥路径
:param alipay_public_key_path: 支付宝公钥路经
:param is_sandbox: 是否是沙箱模式
:param default_notify_url: 默认通知地址
"""
self.appid = appid
self.default_notify_url = default_notify_url
self.return_url = return_url
self.sandbox = is_sandbox
self.alipay_gateway_url = 'https://openapi.alipay.com/gateway.do?' if not self.sandbox else 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?'
self.app_private_key_string = self.read_secret(app_private_key_path)
self.alipay_public_key_string = self.read_secret(alipay_public_key_path)
self.alipay = AliPay(
appid=self.appid,
app_notify_url=self.default_notify_url,
app_private_key_string=self.app_private_key_string,
alipay_public_key_string=self.alipay_public_key_string,
sign_type="RSA2",
debug=True,
verbose=True, # 输出调试数据
config=AliPayConfig(timeout=15) # 可选,请求超时时间
)
if self.sandbox:
logging.debug('当前为沙箱环境')
@staticmethod
def read_secret(secret_path, import_key=False):
"""
从文件加载秘钥
:param secret_path:
:param import_key: 是否需要导入秘钥
:return:
"""
with open(secret_path, "r") as fp:
return RSA.importKey(fp.read()) if import_key else fp.read()
def create_order(self, out_trade_no, amount, subject, notify_url=None, return_url=None,
pay_type=AlipayType.WEB.value):
"""
创建支付订单
:param out_trade_no: 订单号
:param amount: 金额
:param subject: 订单备注
:param notify_url: 通知地址
:param return_url: 回调地址
:param pay_type: AlipayType支付类型
:return: order_string
"""
trade_client = {
AlipayType.WEB.value: self.alipay.api_alipay_trade_page_pay,
AlipayType.WAP.value: self.alipay.api_alipay_trade_wap_pay,
AlipayType.APP.value: self.alipay.api_alipay_trade_app_pay,
AlipayType.MINI.value: self.alipay.api_alipay_trade_create
}
kwargs = dict(
out_trade_no=out_trade_no,
total_amount=amount,
subject=subject,
notify_url=notify_url
)
pay_type in [AlipayType.WEB.value, AlipayType.WAP.value] and kwargs.update(return_url=return_url)
order_string = trade_client[pay_type](**kwargs)
return self.alipay_gateway_url + order_string
def create_pre_order(self, subject, out_trade_no, amount, notify_url=None):
"""
交易预创建(扫码支付)
:param subject: 订单备注
:param out_trade_no: 订单号
:param amount: 金额
:param notify_url: 通知地址
return {'code': '10000', 'msg': 'Success', 'out_trade_no': '2023102401', 'qr_code': 'https://qr.alipay.com/bax01636yklunuyxijpc002f'}
"""
resp = self.alipay.api_alipay_trade_precreate(
subject=subject,
out_trade_no=out_trade_no,
total_amount=amount,
notify_url=notify_url
)
return resp
def refund(self, out_trade_no, refund_amount):
result = self.alipay.api_alipay_trade_refund(out_trade_no=out_trade_no, refund_amount=refund_amount)
return True if result.get("code") == "10000" else False
def notify_verify(self, data):
"""
验证回调通知:验证 alipay 的异步通知
:param data: 来自支付宝回调 POST 给你的 data,字典格式。
data = {
"subject": "测试订单",
"gmt_payment": "2016-11-16 11:42:19",
"charset": "utf-8",
"seller_id": "xxxx",
"trade_status": "TRADE_SUCCESS",
"buyer_id": "xxxx",
"auth_app_id": "xxxx",
"buyer_pay_amount": "0.01",
"version": "1.0",
"gmt_create": "2016-11-16 11:42:18",
"trade_no": "xxxx",
"fund_bill_list": "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]",
"app_id": "xxxx",
"notify_time": "2016-11-16 11:42:19",
"point_amount": "0.00",
"total_amount": "0.01",
"notify_type": "trade_status_sync",
"out_trade_no": "xxxx",
"buyer_logon_id": "xxxx",
"notify_id": "xxxx",
"seller_email": "xxxx",
"receipt_amount": "0.01",
"invoice_amount": "0.01",
"sign": "xxx"
}
"""
signature = data.pop("sign")
# verification
success = self.alipay.verify(data, signature)
return success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED")