支付宝支付
一. 官方sdk
1.下载
需要下载支付宝沙箱版,如图 1 所示:
地址:https://open.alipay.com/develop/sandbox/tool
登录此应用账号密码,如图 2 所示:
图一:
图二:
2.代码(部分代码)
代码地址:https://pypi.org/project/alipay-sdk-python/
# 依赖安装
pip install alipay-sdk-python
# 下面代码需要修改的字段 《在 1 中沙箱应用中可找到》
"""
server_url
app_id
app_private_key
alipay_public_key
out_trade_no
total_amount
subject
"""
# -*- coding: utf-8 -*-
import logging
import traceback
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
filemode="a",
)
logger = logging.getLogger("")
if __name__ == "__main__":
alipay_client_config = AlipayClientConfig()
# 支付宝网关地址
alipay_client_config.server_url = (
"https://openapi-sandbox.dl.alipaydev.com/gateway.do"
)
# APPID
alipay_client_config.app_id = ""
# 应用私钥
alipay_client_config.app_private_key = ""
# 支付宝公钥
alipay_client_config.alipay_public_key = ""
"""
得到客户端对象。
注意,一个alipay_client_config对象对应一个DefaultAlipayClient,
定义DefaultAlipayClient对象后,alipay_client_config不得修改,
如果想使用不同的配置,请定义不同的DefaultAlipayClient。
logger参数用于打印日志,不传则不打印,建议传递。
"""
client = DefaultAlipayClient(
alipay_client_config=alipay_client_config, logger=logger
)
"""
页面接口示例:alipay.trade.page.pay
"""
# 对照接口文档,构造请求对象
model = AlipayTradePagePayModel()
# out_trade_no 相当于一个订单号,每笔订单不一样
model.out_trade_no = "221213213"
# total_amount 订单价格
model.total_amount = 51
model.subject = "测试1"
model.body = "支付宝测试1"
model.product_code = "FAST_INSTANT_TRADE_PAY"
request = AlipayTradePagePayRequest(biz_model=model)
# 订单交易成功还回的地址
request.return_url = "http://www.baidu.com"
request.notify_url = "http://www.baidu.com/post"
# 得到构造的请求,如果http_method是GET,则是一个带完成请求参数的url,如果http_method是POST,则是一段HTML表单片段
response = client.page_execute(request, http_method="GET")
print("alipay.trade.page.pay response:" + response)
二. 第三方sdk
1. 准备
地址:https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
如图一使用步骤
图一:
(1). 准备
1. 安装
pip install python-alipay-sdk
2. 生成密钥文件 《用支付宝已有的也行》
1. 本人已经生成,如果没有生成过,如图 1 ,第二步点进去生成,需要下载《支付宝开放平台密钥工具,或第三方》。
2. 用下载好的软件生成 公钥 和 私钥,《打开文件位置,就是公私钥文件》
3. 将生成的 公钥 复制到 1 中的 自定义密钥中,保存后会生成 支付宝公钥。
2.代码
(1)创建文件
创建两个文件,***《项目中下面不要有换行》***
app_private.pem 和 public_key_ali.pem
# ----------------------- app_private.pem 文件内容 -----------------------
-----BEGIN RSA PRIVATE KEY-----
在中间放入你的私钥
-----END RSA PRIVATE KEY-----
# ----------------------- public_key_ali.pem 文件内容 -----------------------
-----BEGIN PUBLIC KEY-----
在中间放入你的支付宝公钥
-----END PUBLIC KEY-----
(2)编写代码
# --------------------------------- 初始化-----------------------------------
from alipay import AliPay, DCAliPay, ISVAliPay
from alipay.utils import AliPayConfig
# open 中放入(1)中文件的地址
app_private_key_string = open("yourPrivateKey.key").read() # 私钥
alipay_public_key_string = open("alipayPublicCert.pem").read() # 支付宝公钥
alipay = AliPay(
appid="",
app_notify_url=None, # 默认回调 url
app_private_key_string=app_private_key_string,
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_string=alipay_public_key_string,
sign_type="RSA", # RSA 或者 RSA2
debug=False, # 默认 False
verbose=False, # 输出调试数据
config=AliPayConfig(timeout=15) # 可选,请求超时时间
)
# --------------------------------- 接口-----------------------------------
# 电脑网站支付,需要跳转到:https://openapi.alipay.com/gateway.do? + order_string
order_string = 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" # 可选,不填则使用默认 notify url
)
print("https://openapi-sandbox.dl.alipaydev.com/gateway.do?" + order_string)
三. 封装(第三方)
1. 目录结构
libs
├── iPay # aliapy二次封装包
│ ├── __init__.py # 包文件
│ ├── pem # 公钥私钥文件夹
│ │ ├── alipay_public_key.pem # 支付宝公钥文件
│ │ ├── app_private_key.pem # 应用私钥文件
│ ├── pay.py # 支付文件
└── └── settings.py # 应用配置
2. 代码
公钥私钥文件夹中的文件代码, 参考上面的即可。
(1)pay.py
from alipay import AliPay
from alipay.utils import AliPayConfig
from . import settings
alipay = AliPay(
appid=settings.APP_ID,
app_notify_url=None, # 默认回调 url
# 私钥
app_private_key_string=settings.APP_PRIVATE_KEY_STRING,
# 支付宝的公钥
alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY_STRING,
# RSA 或者 RSA2
sign_type=settings.SIGN,
# 默认 False
debug=settings.DEBUG,
verbose=False, # 输出调试数据
config=AliPayConfig(timeout=15), # 可选,请求超时时间
)
(2)settings.py
真实上线环境替换 “应用私钥”, “支付宝公钥” 和 “应用ID” 即可
import os
# 应用私钥
APP_PRIVATE_KEY_STRING = open(
os.path.join(
os.path.dirname(os.path.abspath(__file__)), "pem", "app_private_key.pem"
)
).read()
# 支付宝公钥
ALIPAY_PUBLIC_KEY_STRING = open(
os.path.join(
os.path.dirname(os.path.abspath(__file__)), "pem", "alipay_public_key.pem"
)
).read()
# 应用ID
APP_ID = "87897989879879879"
# 加密方式
SIGN = "RSA2"
# 是否是支付宝测试环境(沙箱环境),如果采用真是支付宝环境,配置False
DEBUG = True
# 支付网关
GATEWAY = (
"https://openapi-sandbox.dl.alipaydev.com/gateway.do"
if DEBUG
else "https://openapi.alipay.com/gateway.do"
)
3. 支付宝回调接口(两个)
(1)路由
urlpatterns = [
path('success/', PaySuccess.as_view()),
]
(2)视图类
1. get 回调 (给咱们前端用)
2. post回调(给支付宝回调用)
(1)核验的时候需将 result_data 中的签名去除掉《下面代码中 post 请求》
class PaySuccess(APIView):
# 肯定不能有登录认证
def get(self, request, *args, **kwargs):
out_trade_no = request.query_params.get('out_trade_no')
# 去数据库查询
res = Order.objects.filter(out_trade_no=out_trade_no, order_status=1).first()
if res:
# 收到支付宝付款成功,修改了订单状态,返回给前端成功
return APIResponse(msg='恭喜您付款成功,快去学习吧')
else:
return APIResponse(code=101, msg='暂未收到您的付款,请稍后刷新再试')
# 支付宝异步回调处理--》修改订单状态---》支付宝不可能带token
# 这个接口测试不了:咱们需要有公网ip才行
# http://127.0.0.1:8000/api/v1/order/success/ post请求
def post(self, request, *args, **kwargs):
try:
# json编码 --> 是字典
# urlencoded --> querydict ---> dict() ----> 纯字典
# 把 request.data ---> 转成字典格式
result_data = request.data.dict()
out_trade_no = result_data.get('out_trade_no')
trade_no = result_data.get('trade_no')
# 去除掉签名
signature = result_data.pop('sign')
# 核验的时候需将 result_data 中的签名去除掉
result = alipay.verify(result_data, signature)
if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
# 完成订单修改:订单状态、流水号、支付时间
Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1, trade_no=trade_no)
# 完成日志记录
logger.warning('%s订单支付成功' % out_trade_no)
return Response('success')
else:
logger.error('%s订单支付失败' % out_trade_no)
except:
pass
return Response('failed')
#### 支付宝post回调地址一定要准确 ###
NOTIFY_URL = BACKEND_URL + "/api/v1/order/success/"
(3)post 回调格式
# 回调数据格式
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",
# 咱们的uuid
"out_trade_no": "订单号",
"buyer_logon_id": "xxxx",
"notify_id": "xxxx",
"seller_email": "xxxx",
"receipt_amount": "0.01",
"invoice_amount": "0.01",
# 验证签名
"sign": "签名"
}