

Django对接支付宝Alipay支付接口 - xzajyjs
source link: https://www.cnblogs.com/xzajyjs/p/16326410.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Django对接支付宝Alipay支付接口 - xzajyjs - 博客园
最新博客更新见我的个人主页: https://xzajyjs.cn
我们在使用Django构建网站时常需要对接第三方支付平台的支付接口,这里就以支付宝为例(其他平台大同小异),使用支付宝开放平台的沙箱环境进行实验。
我们这里使用一个第三方的AliPay Python SDK
(github)
下面看一下它的基本使用
事实上需要我们网站服务端做的事并不多,只需要生成一个订单向支付宝发出支付请求,等用户支付完毕后向支付宝(通过同步和异步的方式)查询订单、交易信息即可。
在实际生产环境中,需要注意如下各种安全性问题:
由于同步返回的不可靠性,支付结果必须以异步通知或查询接口返回为准,不能依赖同步跳转。
商户系统接收到异步通知以后,必须通过验签(验证通知中的 sign 参数)来确保支付通知是由支付宝发送的。
接收到异步通知并验签通过后,请务必核对通知中的 app_id、out_trade_no、total_amount 等参数值是否与请求中的一致,并根据 trade_status 进行后续业务处理。
在支付宝端,partnerId 与 out_trade_no 唯一对应一笔单据,商户端保证不同次支付 out_trade_no 不可重复;若重复,支付宝会关联到原单据,基本信息一致的情况下会以原单据为准进行支付。
1.准备工作
由于使用真实环境需要商户支付宝账号、上线应用需要审批等流程,我们这里使用支付宝开放平台的沙箱环境
沙箱环境中提供了后面需要的参数如APPID
、APP_PRIVATE_KEY
、ALIPAY_PUBLIC_KEY
、支付宝网关
等。
接下来安装AliPay Python SDK
pip3 install python-alipay-sdk --upgrade
由于是沙箱环境,平台已经提供给我们需要的公钥和私钥,如果是生产环境,则需要通过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
在支付宝上下载的公钥是一个字符串,你需要在文本的首尾添加标记位:
-----BEGIN PUBLIC KEY----- 和 -----END PUBLIC KEY-----
2.创建订单
先在settings.py
中设定一些关键参数
# 读取公钥和私钥为字符串 app_private_key_string = open("/path/to/your/private/key.pem").read() alipay_public_key_string = open("/path/to/alipay/public/key.pem").read() # 沙箱环境提供的APPID ALIPAY_APP_ID = "2021000120607609" # 同步回调url(这里需要一个公网ip) RETURN_URL = "http://xxx.xxx.xxx.xxx/" # 支付宝网关地址。注意:正式环境和沙箱环境的网关地址不同 GATEWAY = "https://openapi.alipaydev.com/gateway.do?"
from alipay import AliPay, AliPayConfig from .settings import APP_PRIVATE_KEY, ALIPAY_PUBLIC_KEY, ALIPAY_APP_ID, RETURN_URL, GATEWAY def create_alipay(): # 使用应用公钥进行报文验签 alipay = AliPay( appid=ALIPAY_APP_ID, app_notify_url=None, # 默认异步回调 url app_private_key_string=APP_PRIVATE_KEY, alipay_public_key_string=ALIPAY_PUBLIC_KEY, sign_type="RSA2", debug=False, # 默认 False verbose=False, # 输出调试数据 config=AliPayConfig(timeout=15) # 可选,请求超时时间 ) return alipay
下面可以创建支付订单了(官方文档)
# 向支付宝提交订单信息 def alipay_pay(subject, total_amount, out_trade_no, return_url_view): alipay = create_alipay() # 先实例化alipay return_url = RETURN_URL + return_url_view # 同步回调url,用于支付完后跳转回网站并对支付状态进行即时检验。这里的return_url_view是用于接收支付宝回调的状态检验的视图函数 order_string = alipay.api_alipay_trade_page_pay( out_trade_no=out_trade_no, # 商户订单号,这个需要商户自定义 total_amount=total_amount, # 支付总金额 subject=subject, # 订单标题 return_url=return_url, # 同步回调url,用于支付完后跳转回网站并对支付状态进行即时检验 notify_url="https://example.com/notify" # 可选,不填则使用默认 notify url ) return order_string # 返回订单字符串
import string import random from .settings import GATEWAY # 随机生成32位商户交易号 out_trade_no = "".join(random.sample(string.ascii_letters+string.digits, 32)) # 在视图函数对alipay_return进行绑定 # 同步回调url为: http://xxx.xxx.xxx.xxx/alipay_return order_string = alipay_pay(subject="测试商品",total_amount=100,out_trade_no=out_trade_no,return_url_view='alipay_return') return HttpResponseRedirect(GATEWAY+order_string)
调用后会跳转到支付宝平台,使用沙箱环境提供的买家账号即可完成支付
但是此时我们还不能回调跳转到我们自己的网站,也不能获得订单支付信息,下面还有最后一步。
3.同步回调
我们刚刚创建的订单信息中填写了return_url
,我们需要一个视图函数来接收,并对其返回值进行分析
def alipay_return(request): processed_dict = {} # 回调时alipay会把一些公用信息通过GET方式传参回来,这里用字典去接收存储 for key, value in request.GET.items(): processed_dict[key] = value """ processed_dict = { 'charset': 'utf-8', 'out_trade_no': 'xxxxxxx', # 这个是我们之前创建订单时生成的商户交易号 'method': 'alipay.trade.page.pay.return', 'total_amount': '100.00', # 交易金额 'trade_no': '20220xxxxxxxx24353', # 支付宝交易号 'auth_app_id': '2021xxxxxx609', # 用户appid 'version': '1.0', 'app_id': '2021xxxxxx7609', # 沙箱提供的APPID 应用ID 'sign_type': 'RSA2', 'seller_id': '2088xxxxx844', # 收款支付宝账号对应的支付宝唯一用户号。 以2088开头的纯16位数字 'timestamp': '2022-05-28 23:40:55' } """ sign = processed_dict.pop("sign", None) new_alipay = create_alipay() verify_re = new_alipay.verify(processed_dict, sign) if verify_re is True: print("支付成功") else: print("支付失败")
注意:同步回调往往不可靠,因此需要增加一个异步回调检验
另外,在订单创建后需要向数据库存储订单信息,包括订单金额、商户订单号、appid等,等待回调后与参数校验一致无误后再将订单支付信息进行更新。下面的完整示例不会包括该部分,请自行完成
# alipay.py from alipay import AliPay, AliPayConfig from .settings import APP_PRIVATE_KEY, ALIPAY_PUBLIC_KEY, ALIPAY_APP_ID, RETURN_URL def create_alipay(): alipay = AliPay( appid=ALIPAY_APP_ID, app_notify_url=None, # 默认回调 url app_private_key_string=APP_PRIVATE_KEY, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, alipay_public_key_string=ALIPAY_PUBLIC_KEY, sign_type="RSA2", # RSA 或者 RSA2 debug=False, # 默认 False verbose=False, # 输出调试数据 config=AliPayConfig(timeout=15) # 可选,请求超时时间 ) return alipay def alipay_pay(subject, total_amount, out_trade_no, return_url_view): alipay = create_alipay() return_url = RETURN_URL + return_url_view order_string = alipay.api_alipay_trade_page_pay( out_trade_no=out_trade_no, total_amount=total_amount, subject=subject, return_url=return_url, notify_url="https://example.com/notify" # 可选,不填则使用默认 notify url ) return order_string
# settings.py ... ... ALIPAY_APP_ID = "xxxxxx" APP_PRIVATE_KEY = open(os.path.join(BASE_DIR, 'alipay/app_private_key.pem'), 'r').read() ALIPAY_PUBLIC_KEY = open(os.path.join(BASE_DIR, 'alipay/alipay_public_key.pem'), 'r').read() RETURN_URL = "http://xxxxxx/" GATEWAY = "https://openapi.alipaydev.com/gateway.do?"
# urls.py from django.contrib import admin from django.urls import path from . import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index), path('alipay_return/', views.alipay_return) ]
# views.py import random import string from django.http import HttpResponseRedirect from django.shortcuts import render from ali_django.alipay import alipay_pay, create_alipay from django.conf import settings def index(request): if request.method == "GET": return render(request, 'index.html') elif request.method == "POST": # 随机生成32位商户交易号 out_trade_no = "".join(random.sample(string.ascii_letters + string.digits, 32)) order_string = alipay_pay(subject="测试商品", total_amount=100, out_trade_no=out_trade_no,return_url_view='alipay_return') return HttpResponseRedirect(settings.GATEWAY + order_string) def alipay_return(request): processed_dict = {} # 回调时alipay会把一些公用信息通过GET方式传参回来,这里用字典去接收存储 for key, value in request.GET.items(): processed_dict[key] = value sign = processed_dict.pop("sign", None) new_alipay = create_alipay() verify_re = new_alipay.verify(processed_dict, sign) if verify_re is True: print("支付成功") else: print("支付失败")
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>支付宝支付接口测试</title> </head> <body> <form action="" method="post"> <input type="submit" value="提交"> </form> </body> </html>
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK