草庐IT

Django对接支付宝Alipay支付接口

子非鱼 2023-03-28 原文

最新博客更新见我的个人主页: 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.准备工作

由于使用真实环境需要商户支付宝账号、上线应用需要审批等流程,我们这里使用支付宝开放平台的沙箱环境

沙箱环境中提供了后面需要的参数如APPIDAPP_PRIVATE_KEYALIPAY_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>

有关Django对接支付宝Alipay支付接口的更多相关文章

  1. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  2. ruby-on-rails - 与 ActiveMerchant 一起使用的最佳支付网关是什么? - 2

    我需要使用ActiveMerchant库在我们的一个Rails应用程序中设置支付解决方案。尽管这个问题非常主观,但人们对主要网关(BrainTree、Authorize.net等)的体验如何?它必须:处理定期付款。有能力记入个人帐户。能够取消付款。有办法存储用户的付款详细信息(例如Authotize.netsCIM)。干杯 最佳答案 ActiveMerchant很棒,但在过去一年左右的时间里,我在使用它时发现了一些问题。首先,虽然某些网关可能会得到“支持”——但并非所有功能都包含在内。查看功能矩阵以确保完全支持您选择的网关-http

  3. ruby-on-rails - 如何在 RubyOnRails 中使用 'acts as nested set' 创建一个可排序的接口(interface) - 2

    我一直在为使用acts_as_list的模型实现一些不错的交互界面,这些界面可以对我的mRails应用程序中的列表进行排序。我有一个排序函数,在每次拖放之后使用sortable_elementscript.aculo.us函数调用并设置每条记录的位置。这是在拖放完成后处理排序的Controller操作示例:defsortparams[:documents].each_with_indexdo|id,index|Document.update_all(['position=?',index+1],['id=?',id])endend现在我正在尝试对嵌套集模型(acts_as_nested

  4. ruby-on-rails - 在 Ruby on Rails 中验证 Django 密码给出不匹配的密码 - 2

    我正在用RubyonRails重写Django应用程序,并希望为用户保留旧密码。Django使用PBKDF2SHA1作为加密机制。所以我有一个加密密码是这个pbkdf2_sha256$10000$YsnGfP4rZ1IZ$Tpf4922MoNEjuJQA9EG2Elptyt3dMAyzBPUgmunFOW4=原密码是2bulls在Ruby中,我使用PBKDF256gem和base64进行检查。Base64.encode64PBKDF256.dk("2bulls","YsnGfP4rZ1IZ",10000,32)我很期待Tpf4922MoNEjuJQA9EG2Elptyt3dMAyzBP

  5. 你真正了解什么是接口测试么?接口实战一“篇”入魂 - 2

    最近在工作中,看到一些新手测试同学,对接口测试存在很多疑问,甚至包括一些从事软件测试3,5年的同学,在聊到接口时,也是一知半解;今天借着这个机会,对接口测试做个实战教学,顺便总结一下经验,分享给大家。计划拆分成4个模块跟大家做一个分享,(接口测试、接口基础知识、接口自动化、接口进阶)感兴趣的小伙伴记得关注,希望对你的日常工作和求职面试,带来一些帮助。注:文章较长有5000多字,希望小伙伴们认真看完,当然有些内容对小白同学不是太友好,如果你需要详细了解其中的一些概念或者名词,请在文章之后留言,后续我将针对大家的疑问,整理输出一些大家感兴趣的文章。随着开发模式的迭代更新,前后端分离已不是新的概念,

  6. Spring Boot中的微信支付(小程序) - 2

    前言微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的。一、申请流程和步骤图1-1注册微信支付账号获取微信小程序APPID获取微信商家的商户ID获取微信商家的API私钥配置微信支付回调地址绑定微信小程序和微信支付的关系搭建SpringBoot工程编写后台支付接口发布部署接口服务项目使用微信小程序或者UniAPP调用微信支付功能支付接口的封装配置jwt或者openid的token派发原生微信小程序完成支付对接二、注册商家2.1商户平台商家或者企业想要通过微信支付来进行商品的销售,必须先通过微信平台(pay.weixin.qq.com)去将商家进行注册。注册成

  7. 基于python的短视频智能推荐/django的影视网站/视频推荐系统 - 2

    摘要本论文主要论述了如何使用Python技术开发一个短视频智能推荐,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述短视频智能推荐的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程,对系统进行各个阶段分析设计。 短视频智能推荐的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、热门视频管理、用户上传管理、系统管理,用户:首页、个人中心、用户上传管理、我的收藏管理,前台首页;首页、热门视频、用户上传、公告信息、个人中心、后台管理等功能。由于本网站的功能模块设计比较全面,所以使得整个短视频智能推荐信

  8. ruby-on-rails - 在 Ruby on Rails 中为由外部 API 支持的模型使用 ActiveRecord 接口(interface) - 2

    我正在尝试在我的Rails应用程序中使用模型来从外部API检索信息。我想做的是以类似于ActiveRecord模型提供的方式(特别是关联,以及相同风格的可链接查询方法)访问我的数据模型(可能包含来自多个API调用的信息)。我最初的直觉是重新创建我想要的ActiveRecord部分并合并此API。不想“重新发明轮子”并确切地看到添加更多功能需要多少工作让我退后一步并重新评估如何处理这个问题。我找到了在没有表的情况下使用ActiveRecord的方法(请参阅:Railscast#193TablelessModel和博客文章here)并研究了ActiveRecord。因为ActiveMode

  9. [译]在C#中使用IComparable和IComparer接口 - 2

    原文:UsetheIComparableandIComparerinterfacesinVisualCSharp本文介绍了在VisualC#中如何使用IComparer和IComparable接口。概要本文同时讨论了IComparable和IComparer接口,原因有两点。这两个接口经常一起使用。虽然接口类似且名称相似,但它们却有不同的用途。如果你有一个支持IComparer的类型数组(例如字符串或整数),你可以对它进行排序而不需要提供任何对IComparer的显式引用(译注:意思是把一个IComparer的实现类作为参数传递给排序方法)。在这种情况下,数组元素会被转换为IComparer的

  10. API淘宝数据接口 - 2

    如果你想在自己的应用中使用淘宝的数据,那么对接淘宝数据接口是必不可少的一步。本文将介绍如何对接API淘宝数据接口,以便你能够顺利获取和使用淘宝的数据。步骤一:​​获取AppKey和AppSecret​​首先,在淘宝开放平台申请API接口之前,需要先注册为淘宝开发者并创建应用。创建应用后,你将得到一个AppKey和AppSecret,这两个参数需要在调用API接口时用于身份验证。步骤二:确定需要调用的API接口在淘宝开放平台的开发文档中,你将找到所有可用的API接口。你需要根据你的需求找到需要调用的API接口,例如查询商品、店铺等信息。在找到需要的API接口后,你需要了解该接口的请求参数和返回结

随机推荐