django实现支付宝付款功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django实现支付宝付款功能相关的知识,希望对你有一定的参考价值。

支付宝支付功能
 
登录支付宝官网开发平台
下载SDK,
支付宝并没有python版本SDK
SDK有实例和代码。
没有python则自己写,或者去github找。
 
本次利用alipay这个组件。
 
先安装一个pycrytodome
pip3 install pycrytodome
 
技术分享图片

 

如果真实环境,按上面这个来注册。
测试环境需要用沙箱环境。
 
技术分享图片

向支付宝提交的这个链接,在测试模式有dev,生产环境删掉dev

 
技术分享图片

 

 技术分享图片

 

 公钥复制到支付宝里,私钥存到自己django文件中,自己文件的公钥是来自支付宝的公钥。
 
技术分享图片
上面沙箱环境不需要配置。
下面是创建一个生产环境的应用。
 技术分享图片

技术分享图片

以下为支持的功能

 技术分享图片

技术分享图片

以上为真实生产需要的操作。
 
然后之后看pay项目代码。
 
技术分享图片

 

以上为目录结构。
 
 
 views.py:
 1 from django.shortcuts import render, redirect, HttpResponse
 2 from utils.pay import AliPay
 3 import json
 4 import time
 5 
 6 
 7 def ali():
 8     # 商户app_id
 9     app_id = "2016082600312402" #复制来自支付宝生成的id
10     # 服务器异步通知页面路径 需http: // 格式的完整路径,不能加?id = 123 这类自定义参数,必须外网可以正常访问
11     # 发post请求
12     notify_url = "http://www.xxxx.com:8009/page2/"  #将这两个链接复制到支付宝中
13 
14     # 页面跳转同步通知页面路径 需http: // 格式的完整路径,不能加?id = 123 这类自定义参数,必须外网可以正常访问
15     # 发get请求
16     return_url = "http://www.xxxx.com:8009/page2/"
17     # 商户私钥路径
18     merchant_private_key_path = "keys/pri"   #设置公钥和私钥的地址,文件上下两行begin和end是必须的,公钥就放在第二行。
19     # 支付宝公钥路径
20     alipay_public_key_path = "keys/pub"
21 
22     alipay = AliPay(
23         appid=app_id,
24         app_notify_url=notify_url,
25         return_url=return_url,
26         app_private_key_path=merchant_private_key_path,
27         alipay_public_key_path=alipay_public_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥
28         debug=True,  # 默认False,
29     )
30     return alipay
31 
32 
33 def page1(request):
34     if request.method == "GET":
35         return render(request, page1.html)
36     else:
37         money = float(request.POST.get(money))
38         alipay = ali()
39         # 生成支付的url
40         query_params = alipay.direct_pay(
41             subject="充气式减压玩具",  # 商品简单描述
42             out_trade_no="x2" + str(time.time()),  # 商户订单号
43             total_amount=money,  # 交易金额(单位: 元 保留俩位小数)
44         )
45 
46         pay_url = "https://openapi.alipaydev.com/gateway.do?{}".format(query_params)
47         #支付宝网关链接,去掉dev就是生产环境了。
48         return redirect(pay_url)
49 
50 
51 def page2(request):
52     alipay = ali()
53     if request.method == "POST":
54         # 检测是否支付成功
55         # 去请求体中获取所有返回的数据:状态/订单号
56         from urllib.parse import parse_qs
57 
58         # request.body                  => 字节类型
59         # request.body.decode(‘utf-8‘)  => 字符串类型
60         """
61         {"k1":["v1"],"k2":["v1"]}
62         k1=[v1]&k2=[v2]
63         """
64         body_str = request.body.decode(utf-8)
65         post_data = parse_qs(body_str)
66         # {k1:[v1,],k2:[v2,]}
67 
68         # {k1:v1}
69         post_dict = {}
70         for k, v in post_data.items():
71             post_dict[k] = v[0]
72 
73 
74         print(post_dict)
75         """
76         {‘gmt_create‘: ‘2017-11-24 14:53:41‘, ‘charset‘: ‘utf-8‘, ‘gmt_payment‘: ‘2017-11-24 14:53:48‘, ‘notify_time‘: ‘2017-11-24 14:57:05‘, ‘subject‘: ‘充气式韩红‘, ‘sign‘: ‘YwkPI9BObXZyhq4LM8//MixPdsVDcZu4BGPjB0qnq2zQj0SutGVU0guneuONfBoTsj4XUMRlQsPTHvETerjvrudGdsFoA9ZxIp/FsZDNgqn9i20IPaNTXOtQGhy5QUetMO11Lo10lnK15VYhraHkQTohho2R4q2U6xR/N4SB1OovKlUQ5arbiknUxR+3cXmRi090db9aWSq4+wLuqhpVOhnDTY83yKD9Ky8KDC9dQDgh4p0Ut6c+PpD2sbabooJBrDnOHqmE02TIRiipULVrRcAAtB72NBgVBebd4VTtxSZTxGvlnS/VCRbpN8lSr5p1Ou72I2nFhfrCuqmGRILwqw==‘, ‘buyer_id‘: ‘2088102174924590‘, ‘invoice_amount‘: ‘666.00‘, ‘version‘: ‘1.0‘, ‘notify_id‘: ‘11aab5323df78d1b3dba3e5aaf7636dkjy‘, ‘fund_bill_list‘: ‘[{"amount":"666.00","fundChannel":"ALIPAYACCOUNT"}]‘, ‘notify_type‘: ‘trade_status_sync‘, ‘out_trade_no‘: ‘x21511506412.4733646‘, ‘total_amount‘: ‘666.00‘, ‘trade_status‘: ‘TRADE_SUCCESS‘, ‘trade_no‘: ‘2017112421001004590200343962‘, ‘auth_app_id‘: ‘2016082500309412‘, ‘receipt_amount‘: ‘666.00‘, ‘point_amount‘: ‘0.00‘, ‘app_id‘: ‘2016082500309412‘, ‘buyer_pay_amount‘: ‘666.00‘, ‘sign_type‘: ‘RSA2‘, ‘seller_id‘: ‘2088102172939262‘}
77         {‘stade_status‘: "trade_success",‘order‘:‘x2123123123123‘}
78         """
79         sign = post_dict.pop(sign, None)
80 
81         status = alipay.verify(post_dict, sign)
82         if status:
83             print(post_dict[stade_status])
84             print(post_dict[out_trade_no])
85 
86         return HttpResponse(POST返回)
87     else:
88         # QueryDict = {‘k‘:[1],‘k1‘:[11,22,3]}
89         params = request.GET.dict()
90         sign = params.pop(sign, None)
91         status = alipay.verify(params, sign)
92         print(GET验证, status)
93         return HttpResponse(支付成功)

 

key目录

技术分享图片
-----BEGIN RSA PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZWExNxlfrbIknZmVwzK8MNYkP8aW2XChMNUD/+Gi3OC/k417Q6C326nxlYQy3FbsjPBofVapbeHY2y0J3t3m1tIuH3MBDqAM2pt3mExl7xr8hBROfD71V39XplJhE2WRPN2BdJLiYVYXgTTkpXunA1zsbt0gdmQK2VoQj3cdy7EukUferBRwsxxIe0neCPWwq4DlQeHu94csA3smXZLyOt8fovd4ksiphQ3U5R/aNCxV0vY47zSWK+jYKQUzpbRidVeQX3nT9G6M8w7b5rlCB1VZQBLwiVfYCVNTxcTN8qI5NaMvbWeKrr0YNRTKKzn2qL4CKLuyDoCMXo+cyDnnFAgMBAAECggEAFqTobkH37wND1uMINpRcuHzrZsnaZgF8AVSbDRAoeM5VzxcRTdqiz1Lm2vkdhgWxlZ4xaopWUWlfh53tsuNevtusnd8V+PaMPylrfQkIYqj2SM5qmOve4g+MDeX5Z1Lu7IHsfEfTI6vlYtUo23KUEA9cjSqvTMYgTjb9VW9J1GMw5ccPkret2Emp1ThzaUzaetcGkSbllFuHSlwZ2fu6egxQPNZHDmyuH708cxW8FyB7ilR23cMqTXh4u5ytEEkt6mRb9xman8D7yaE7JEBlXSKCvZBDv73qsuEIHSI3tomLIB5l0kxV58gq90giTnPnwcwn4ylJypUMfTr8O6JFAQKBgQDvzrUOM0XrPhg8aP5suzvV/MhP3z+F4Fm7Z5eBS3HiGq1lYzqhzjCE9bZ7uXwYbvLvLf8lpWsubeU/dO0Ts6yfm4yr43sOsIpuBWoQK+MQIriDkeMeld4+adbEFFxyPSATdpEvz8pUqsWAdTAF5/kawQXtUiSbbPLHtDNf3Nc/MQKBgQDoBU4gcLnrzA7i8xSn4YqEpR0brQGE0L4QRx4IVLzYvKv3swJqM9+B3ICrgJ1B9zr+IPN0DTu4ZunWyVDmFxLfwMNuqg5zmHeUf+XYY3toDm7co1LoFXp5oMA9n6fYKlcTvz1d7mK0sQ0P2adWFLp1cX0yEEEFNVCPV8L1KcfG1QKBgHT8TwEdbDeFdEdMJQogEOGkTogAbbm+p6evso5Fosndn8c9MCYtMyg5wgr7gplczrB1rOnNl8rvm41oWhtpZIX8WRSlhau13eIsTACVmFCPz5mHutd53xBti3LeR/cG8LXt+ofrg1XodS7kfEf1UWWG0oBiuS8FaC6aLxHN50eRAoGBAJv4tQRpwxIYIwm9ju0sWQnCVUb9jj/Sc3JN3IqNLEYmzxO8aqsqI94QdQ7VbuGhaS7cx8wD+VmFFT0mKBQE/tMbqkUCXKSoofpZ4BEPDy5sRWpdAKaziZmpzpGeeh5+l/rWXFKApioBu14kWrErTg0VNawp8QunQ3iY7p4QcBPhAoGADWv4kbu6ln/mO85t9/8KtNS883J+EWqg6RzyC+1l1UhM3+k7gjCPqaBtb4yGas2bkcSPbl8oq7inSWfCap5zmTkzcrrS3BxQuHH4XDRoqB/vrGHP5gD+KpfZxD+rFscfjVlk5FwhnYHrlRzE/kZr+MGOrtvc9TaluYzR0g18/dU=
-----END RSA PRIVATE KEY-----
pri 私钥
技术分享图片
1 -----BEGIN PUBLIC KEY-----
2 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAstVlLwOTcg64SiT4GiHOlToRxz88r3zjWX2N1juX86fa+UYtq33TfXZgh1rVl67dLJC7ICh4BYCrq1+JkMiyah0oOC6EVdLBWcKDrNV19ig5oetTuEO3Vbji/rU3nUYun24MmOJKca3xf4UL192pM5w+/mNHPLLHJBeoMjDWVJehURRw/PDGLv6+QFnC9LwihcR5vWr7x0lBAGJsPqRv9RUB0UWXj/AzxDeD6GGlHMS4tYwwYi6JQRHf9yA+dWDD4YTUc3UBb/WQx954ET/BW+KTFQzNwxryqr3XmucnZmkiNfTkmdGoH+J0zpVXSqHAvLkFJ9UERYUrUq0Bz6CpqQIDAQAB
3 -----END PUBLIC KEY-----
pub 公钥文件

settings文件

技术分享图片
DEBUG = True

ALLOWED_HOSTS = [*]
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,
]#注意以上
settings

url

技术分享图片
from django.conf.urls import url
from django.contrib import admin
from app import views
urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^page1/, views.page1),
    url(r^page2/, views.page2),
]
url

html

技术分享图片
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link rel="stylesheet" href="dist/css/bootstrap.css">
 7 </head>
 8 <body>
 9     <form method="POST">
10         {% csrf_token %}
11         <input type="text" name="money">
12         <input type="submit" value="去支付" />
13     </form>
14 
15 
16 <script></script>
17 </body>
18 </html>
html

utils

技术分享图片
  1 from datetime import datetime
  2 from Crypto.PublicKey import RSA
  3 from Crypto.Signature import PKCS1_v1_5
  4 from Crypto.Hash import SHA256
  5 from urllib.parse import quote_plus
  6 from urllib.parse import urlparse, parse_qs
  7 from base64 import decodebytes, encodebytes
  8 import json
  9 
 10 class AliPay(object):
 11     """
 12     支付宝支付接口(PC端支付接口)
 13     """
 14 
 15     def __init__(self, appid, app_notify_url, app_private_key_path,
 16                  alipay_public_key_path, return_url, debug=False):
 17         self.appid = appid
 18         self.app_notify_url = app_notify_url
 19         self.app_private_key_path = app_private_key_path
 20         self.app_private_key = None
 21         self.return_url = return_url
 22         with open(self.app_private_key_path) as fp:
 23             self.app_private_key = RSA.importKey(fp.read())
 24         self.alipay_public_key_path = alipay_public_key_path
 25         with open(self.alipay_public_key_path) as fp:
 26             self.alipay_public_key = RSA.importKey(fp.read())
 27 
 28         if debug is True:
 29             self.__gateway = "https://openapi.alipaydev.com/gateway.do"
 30         else:
 31             self.__gateway = "https://openapi.alipay.com/gateway.do"
 32 
 33     def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
 34         biz_content = {
 35             "subject": subject,
 36             "out_trade_no": out_trade_no,
 37             "total_amount": total_amount,
 38             "product_code": "FAST_INSTANT_TRADE_PAY",
 39             # "qr_pay_mode":4
 40         }
 41 
 42         biz_content.update(kwargs)
 43         data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
 44         return self.sign_data(data)
 45 
 46     def build_body(self, method, biz_content, return_url=None):
 47         data = {
 48             "app_id": self.appid,
 49             "method": method,
 50             "charset": "utf-8",
 51             "sign_type": "RSA2",
 52             "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
 53             "version": "1.0",
 54             "biz_content": biz_content
 55         }
 56 
 57         if return_url is not None:
 58             data["notify_url"] = self.app_notify_url
 59             data["return_url"] = self.return_url
 60 
 61         return data
 62 
 63     def sign_data(self, data):
 64         data.pop("sign", None)
 65         # 排序后的字符串
 66         unsigned_items = self.ordered_data(data)
 67         unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
 68         sign = self.sign(unsigned_string.encode("utf-8"))
 69         # ordered_items = self.ordered_data(data)
 70         quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)
 71 
 72         # 获得最终的订单信息字符串
 73         signed_string = quoted_string + "&sign=" + quote_plus(sign)
 74         return signed_string
 75 
 76     def ordered_data(self, data):
 77         complex_keys = []
 78         for key, value in data.items():
 79             if isinstance(value, dict):
 80                 complex_keys.append(key)
 81 
 82         # 将字典类型的数据dump出来
 83         for key in complex_keys:
 84             data[key] = json.dumps(data[key], separators=(,, :))
 85 
 86         return sorted([(k, v) for k, v in data.items()])
 87 
 88     def sign(self, unsigned_string):
 89         # 开始计算签名
 90         key = self.app_private_key
 91         signer = PKCS1_v1_5.new(key)
 92         signature = signer.sign(SHA256.new(unsigned_string))
 93         # base64 编码,转换为unicode表示并移除回车
 94         sign = encodebytes(signature).decode("utf8").replace("\n", "")
 95         return sign
 96 
 97     def _verify(self, raw_content, signature):
 98         # 开始计算签名
 99         key = self.alipay_public_key
100         signer = PKCS1_v1_5.new(key)
101         digest = SHA256.new()
102         digest.update(raw_content.encode("utf8"))
103         if signer.verify(digest, decodebytes(signature.encode("utf8"))):
104             return True
105         return False
106 
107     def verify(self, data, signature):
108         if "sign_type" in data:
109             sign_type = data.pop("sign_type")
110         # 排序后的字符串
111         unsigned_items = self.ordered_data(data)
112         message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
113         return self._verify(message, signature)
utils

 

 如果需要测试,需要用公网可以直接访问的url,

我们可以通过自己单机测试,更改本机hosts文件,将本机ip和views里return_url一致。

更改C:\Windows\System32\drivers\etc\hosts  

 最后从支付宝下载对应的沙河手机app,充值之后就可以付款了,快去尝试吧。
 
 
 
 
 
 
 
 

以上是关于django实现支付宝付款功能的主要内容,如果未能解决你的问题,请参考以下文章

支付宝微信扫同一个二维码也可以付款怎么弄?

thinkphp有没有集成支付宝双功能付款的详细教程呢,在网上找了好多,出现好多问题,求大神指点。

外部跳转到支付宝

如何用django实现用支付宝支付

支付宝下载|支付宝app下载

支付宝支付集成