signed

QiShunwang

“诚信为本、客户至上”

python中使用支付宝,支付成功后回调通知,返回给后端,网上教程很多,没有完整的dmeo,为此,这是一个完整版的python支付,需要的自己提取,有问题可以交流

2021/1/28 13:05:38   来源:

首先配置支付宝,这里使用的是沙箱环境
沙箱环境配置
支付宝接口官方地址
第一步:选择研发服务
在这里插入图片描述

第二步:配置沙箱应用

在这里插入图片描述

第三步:设置
在这里插入图片描述

第四步:这里配置秘可以选择两种当时(第一种:使用支付宝助手进行生成,第二种:使用openssl生成)
支付宝助手生成如下
在这里插入图片描述

这里选择RSA2和PKCS1
第五步:在支付宝沙箱中配置秘钥
在这里插入图片描述

将秘钥按照要求复制过来即可

沙箱账户
在这里插入图片描述

在测试的时候使用买家信息进行登录支付
沙箱配置好的了

python代码如下
这里使用的是alipay-sdk-python,这个是已经过时的,最新的是python-alipay-sdk,暂且使用alipay-sdk-python进行开发测试,后续使用python-alipay-sdk
alipay-sdk-python在安装过程中可能会出现以下问题

ModuleNotFoundError: No module named 'Crypto'
pip uninstall Crypto
pip install pycryptodome

alipay-sdk-python这个是不能直接通过pip install alipay-sdk-python进行安装的

我们需要到网上进行下载

下载后解压
在这里插入图片描述

这里需要修改setup.py文件
修改下面的代码,然后使用手动安装
在这里插入图片描述

手动安装教程
在这里插入图片描述

第二步:切换到项目的虚拟环境下面
在这里插入图片描述

第三步:进行安装

python srtup.py  install

在这里插入图片描述

django应用例子
先创建一个apps

'website',

在setting.py中 这是我的配置文件 不要无脑型的把我setting.py直接复制过去替换
只需要下面三个地方修改一下就行

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Django settings for alipaydemo3 project.

Generated by 'django-admin startproject' using Django 3.1.5.

For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
import os
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ak#h4k#+cdjnsumvka6sxd0(dbjw!i!x%tuz5#m!1iq=hqmvsl'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'website',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'alipaydemo3.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'alipaydemo3.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'
# APPID
ALIPAY_APPID = "2021********673"  # 沙箱APPID,生产环境须更改为应用APPID。

# 网关
ALIPAY_URL = "https://openapi.alipaydev.com/gateway.do"  # 沙箱网关,生产环境须更改为正式网关。
# ALIPAY_URL = "https://openapi.alipay.com/gateway.do" # 正式网关,开发环境勿使用。

# 回调通知地址
ALIPAY_NOTIFY_URL = "http://127.0.0.1:8000/pay_result/"  # 如果只可以内网访问开发服务器
# ALIPAY_NOTIFY_URL = "http://127.0.0.1:8000/pay_result/"  # 生产环境或外网可以访问开发服务器

# 使用密钥文件
APP_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'website/keys/应用私钥2048.txt')
ALIPAY_PUBLIC_KEY_PATH = os.path.join(BASE_DIR, 'website/keys/应用公钥2048.txt')

# 使用密钥字符串
APP_PRIVATE_KEY = 'MIIEpAIBAAKjuM5ESMbwLlyEf4gQEB+wE/gZpheEviZVBI2EMsQeMrp4pH2aRmKFiC1lCh2Rpx9OQLfFgazkuZoNS0zVawxweamQCfU0gSx1cHnJTkouExYLgGsiKWxEaVw2SULnMH1B7vO4Jga1mm+IO/99iWOfe3iOM4EaAbZ/80q6fTqVvJ6gBz6JfA7Vg1CCYtYx4Kn3RqVMROGvqdl302PLB+MRWrRN8FYxiMRgZIqW+GQxFDd7AlbvoCfMoh1Np7v5Iv2YE79RYWKzwcaKYmrCr9kTz/CExpw4+2N0OWmyqIt6MoT90Cq1W3vDG11W5QKQIDAQABAoIBAQCbmP/NgtgV0cIQuhTqpI6vLIA519y44mdbKU3Lz88yhDR+OWsvMfC/KW0kmhS8lD/c5zDpoY3yMX5ok8UkiLJaUvzoQCNC+aHROrGpBNfKh95QeVhtQUwup/7AVnqzqOGBHla47GGRb7D00rDJf85TpwstwhjA5T/T/+ILm/6FaXYQMcRtzmHrqSVVzab8hyN0MFWyAjW9KVakUMsNJQj1MfnfiXmcl6uF1JCQdy+NvdQDthb9YyNgJInleK+bMmWied/TfvMCTbYckl0bM/bBbKLGft6CoDK/mcTcm+9PwMW8Bclndh7swXGBDqPAYjLEZVnjcQzMTm8Vw48+nC4BAoGBAPysQNYzQtIkWOWVL5wq99Ulen0yeQvy/yuXa8XZ3X4gDfh0x1L9hij+0hKVrGPKgANZCADykTsuX4dLT7DZ5CMep73TdrDJbsPHRvU77MAmMqxbpSOSrBz2oBiU7MBMQqISBwBb0ZHnLDExksdaSOmGaWGaXHyoT5ZN2TJbROmJAoGBAPyYkXxhtq5xGHzkp68r0QdRv3cJhUeXqzYAuA00d5aAHk83/I8cJqxqzoNW/OWXpXJvV4phKV77zh/EaGAh8tqEsGh0QGzD4ePahjsFQBZRo0iJ4QVcU27V+OGNGB89BS0p8XOLP46NNjqWtSXuqkx/GQP6cZ0F/tYpJMvqjKmhAoGASp4r/5Xf0+M8BYDLMJlX2zBYPgTbznWSebMb9q/iQ08AETGbc5y/M/gc3bQp1saEi3iNbooz7YBCYdgRzq5qOxzgeKSsVoUGGvcMs3tg7VXafSALYrf78Am9OcUxLZDX1LjyLF7xQt88I8L6D7lP8vboxBQr3/xslHyk+cQOU9ECgYACKIuVtIALHYxIBOwp4wX2OgyYx8wLwJAF9hucgUZEUvPvWVsfHe52qrL5DFU84P7Y63qkBBCGb0BjpRn/OEsK8vdO7S9fvoy/la5v8quJhUkP5Z22ngNYfxuRUdNS8QKKUEFv61CvtyUvevoxSMjLvopILmuqG9MBoXhfBbIOAQKBgQDNTklqbDXcvU2ILtqJR14u1MSJPMIknBktQjntD4bvtp5we1l9XcdsQj6FP4lMox4TaPmIseHzFQKYEYxGO+Dz+XI5u9U5DGh+lQ9O4JthmgL/nKGUwWaPcYJKp0TXAlWbNXYbggTWpD8KmHwlTn6LipcVkZ3gn6bc0JeDgoVtDQ=='

#ALIPAY_PUBLIC_KEY = 'MIIBIjANBg4+hIYwdYrYKR4QOKZukjuM5ESMbwLlyEf4gQEB+wE/gZpheEviZVBI2EMsQeMrp4pH2aRmKFiC1lCh2Rpx9OQLfFgazkuZoNS0zVawxweamQCfU0gSx1cHnJTkouExYLgGsiKWxEaVw2SULnMH1B7vO4Jga1mm+IO/99iWOfe3iOM4EaAbZ/80q6fTqVvJ6gBz6JfA7Vg1CCYtYx4Kn3RqVMROGvqdl302PLB+MRWrRN8FYxiMRgZIqW+GQxFDd7AlbvoCfMoh1Np7v5Iv2YE79RYWKzwcaKYmrCr9kTz/CExpw4+2N0OWmyqIt6MoT90Cq1W3vDG11W5QKQIDAQAB'
ALIPAY_PUBLIC_KEY = 'MIIBIjANB9Qv9rx3XRkxHUOqMIoYDurWVE90PWoALE0FkBjjLxcEitCLQhjWf/XZpGJjxunF/iu9HdaNVgDUJoEbAZ6+qeGaYSJJS4RC0le+v41AaIrke/fDAENvX+Aac247fWnoqlmuKPhZtyxp1NsmC05azn3MDuAjtofc9vG3retiyKmCcsstIZpqrfjQAab2b+s8rTbCho5fndWR3iMYC5geTZ2rpxHj8PsxxNra8S10WrnyNNzNYWxqgcEjN9Gl9xhaISlAPYH0rBCzZuMIZj+j/2bV2LxDJYwO3OCC75eB3G+xBOUDpTjloBKbSB+/8hw+kZO16HNrgug8BLZhqYwIDAQAB'


url.py
from django.contrib import admin
from django.urls import path
from website import views as site_view
urlpatterns = [
    path('admin/', admin.site.urls),
    path('buy/', site_view.buy),  # 打开购买页面
    path('to_pay/', site_view.to_pay),  # 跳转支付页面
    path('pay_result/', site_view.pay_result),  # 返回通知验签
]

views.py
from django.shortcuts import render
from django.shortcuts import HttpResponseRedirect
from django.shortcuts import HttpResponse
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  # 网站支付请求类
from alipay.aop.api.util.SignatureUtils import verify_with_rsa
from alipaydemo3 import settings
import random


def buy(request):
    return render(request, 'buy.html')


def to_pay(request):
    alipay_client_config = AlipayClientConfig()  # 创建配置对象
    alipay_client_config.server_url = settings.ALIPAY_URL  # 网关
    alipay_client_config.app_id = settings.ALIPAY_APPID  # APPID
    alipay_client_config.app_private_key = settings.APP_PRIVATE_KEY  # 应用私钥
    client = DefaultAlipayClient(alipay_client_config=alipay_client_config)  # 使用配置创建客户端
    model = AlipayTradePagePayModel()  # 创建网站支付模型
    model.out_trade_no = 'order_%s' % random.randrange(100000, 999999)  # 商户订单号码
    model.total_amount = int(request.GET['quantity']) * float(request.GET['price'])  # 支付总额
    model.subject = request.GET['goods_name']  # 订单标题
    model.body = '一套完整详细的Python入门视频。'  # 订单描述
    model.product_code = 'FAST_INSTANT_TRADE_PAY'  # 与支付宝签约的产品码名称,目前只支持这一种。
    model.timeout_express = '30m'  # 订单过期关闭时长(分钟)
    pay_request = AlipayTradePagePayRequest(biz_model=model)  # 通过模型创建请求对象
    pay_request.return_url = settings.ALIPAY_NOTIFY_URL
    pay_request.notify_url = settings.ALIPAY_NOTIFY_URL  # 设置回调通知地址
    response = client.page_execute(pay_request, http_method='GET')  # 获取支付链接
    return HttpResponseRedirect(response)  # 重定向到支付宝支付页面


def pay_result(request):  # 定义处理回调通知的函数
    if request.method == 'GET':
        params = request.GET.dict()  # 获取参数字典
        if check_pay(params):  # 调用检查支付结果的函数
            '''
                此处编写支付成功后的业务逻辑
            '''
            return HttpResponse('支付成功!')
        else:
            '''
                此处编写支付失败后的业务逻辑
            '''
            return HttpResponse('支付失败!')
    if request.method == 'POST':
        params = request.POST.dict()  # 获取参数字典
        if check_pay(params):  # 调用检查支付结果的函数
            '''
                此处编写支付成功后的业务逻辑
            '''
            # print('支付成功!')
            return HttpResponse('success')  # 返回成功信息到支付宝服务器
        else:
            '''
                此处编写支付失败后的业务逻辑
            '''
            return HttpResponse('')


def check_pay(params):  # 定义检查支付结果的函数
    sign = params.pop('sign', None)  # 取出签名
    params.pop('sign_type')  # 取出签名类型
    params = sorted(params.items(), key=lambda e: e[0], reverse=False)  # 取出字典元素按key的字母升序排序形成列表
    message = "&".join(u"{}={}".format(k, v) for k, v in params).encode()  # 将列表转为二进制参数字符串
    # with open(settings.ALIPAY_PUBLIC_KEY_PATH, 'rb') as public_key: # 打开公钥文件
    try:
        #     status =verify_with_rsa(public_key.read().decode(),message,sign) # 验证签名并获取结果
        status = verify_with_rsa(settings.ALIPAY_PUBLIC_KEY.encode('utf-8').decode('utf-8'), message,
                                 sign)  # 验证签名并获取结果
        return status  # 返回验证结果
    except:  # 如果验证失败,返回假值。
        return False

buy.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>结算</title>
</head>
<body>
<form action="../to_pay/" method="get">
    <p>商品:Python 入门视频</p>
    <input type="hidden" name="goods_name" value="Python 入门视频">
    <p>价格:¥29.00</p>
    <input type="hidden" name="price" value="29.00">
    数量:<input type="number" name="quantity" value="3">
    <p><input type="submit"></p>
</form>
</body>
</html>

测试看效果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

依赖

alipay-sdk-python==3.3.398
asgiref==3.3.1
certifi==2020.12.5
chardet==4.0.0
crypto==1.4.1
Django==3.1.5
idna==2.10
naked==0.1.31
pyasn1==0.4.8
pycryptodome==3.9.9
pytz==2020.5
pyyaml==5.4.1
requests==2.25.1
rsa==4.7
shellescape==3.8.1
six==1.15.0
sqlparse==0.4.1
urllib3==1.26.3
alipay.aop.api.exception.Exception.RequestException: [43a688f1-6106-11eb-b8ef-3497f6d9da53]request sign failed. int() argument must be a string, a bytes-like object or a number, not 'Sequence'

在这里插入图片描述

有问题留言,手把手指导
有完整版demo,直接运行即可测试