现在所有的门户网站还是一下应用,都离不开第三方支付,我们今天讲一下第三方的支付接口也就是支付宝接口付款。
支付宝支付采用了RSA加密签名的安全通信机制,开发者可以通过支付宝的公钥验证消息的来源,同时使用自己的私钥进行信息加密。RSA算法及数字签名机制是服务窗平台与开发者网关安全通信的基础。

支付宝付款流程图

使用支付宝付款流程图

沙箱

在使用支付宝支付的时候,我们就要使用到沙箱功能。
支付宝沙箱网址:https://openhome.alipay.com/platform/appDaily.htm?tab=info

在沙箱应用中,我们需要记住自己的APPID,设置RSA2(SHA256)密钥
设置密钥官方文档:https://opendocs.alipay.com/open/291/105971#LDsXr

根据文档生成自己的应用公钥和密钥。

实现支付宝接口接入

创建一个keys文件夹,存放alipay_public_2048.txt支付宝公钥和app_private_2048.txt应用私钥
支付宝公钥和应用私钥

文档地址:https://docs.open.alipay.com/api

根据文档写一个支付基类pay.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from base64 import decodebytes, encodebytes
import json
import requests

class AliPay(object):
"""
支付宝支付接口(PC端支付接口)
"""

def __init__(self, appid, app_notify_url, app_private_key_path,
alipay_public_key_path, return_url, debug=False):
self.appid = appid
self.app_notify_url = app_notify_url
self.app_private_key_path = app_private_key_path
self.app_private_key = None
self.return_url = return_url
with open(self.app_private_key_path) as fp:
self.app_private_key = RSA.importKey(fp.read())
self.alipay_public_key_path = alipay_public_key_path
with open(self.alipay_public_key_path) as fp:
self.alipay_public_key = RSA.importKey(fp.read())
#debug=True为测试模式,false是上线模式
if debug is True:
self.__gateway = "https://openapi.alipaydev.com/gateway.do"
else:
self.__gateway = "https://openapi.alipay.com/gateway.do"

def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "FAST_INSTANT_TRADE_PAY",
# "qr_pay_mode":4
}

biz_content.update(kwargs)
data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
return self.sign_data(data)
#构造参数体
def build_body(self, method, biz_content, return_url=None):
data = {
"app_id": self.appid,
"method": method,
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"biz_content": biz_content
}

if return_url is not None:
data["notify_url"] = self.app_notify_url
data["return_url"] = self.return_url

return data
#签名数据
def sign_data(self, data):
data.pop("sign", None)
# 排序后的字符串
unsigned_items = self.ordered_data(data)
unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
sign = self.sign(unsigned_string.encode("utf-8"))
# ordered_items = self.ordered_data(data)
quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)

# 获得最终的订单信息字符串
signed_string = quoted_string + "&sign=" + quote_plus(sign)
return signed_string
#订单数据
def ordered_data(self, data):
complex_keys = []
for key, value in data.items():
if isinstance(value, dict):
complex_keys.append(key)

# 将字典类型的数据dump出来
for key in complex_keys:
data[key] = json.dumps(data[key], separators=(',', ':'))

return sorted([(k, v) for k, v in data.items()])

def sign(self, unsigned_string):
# 开始计算签名
key = self.app_private_key
signer = PKCS1_v1_5.new(key)
signature = signer.sign(SHA256.new(unsigned_string))
# base64 编码,转换为unicode表示并移除回车
sign = encodebytes(signature).decode("utf8").replace("\n", "")
return sign

def _verify(self, raw_content, signature):
# 开始计算签名
key = self.alipay_public_key
signer = PKCS1_v1_5.new(key)
digest = SHA256.new()
digest.update(raw_content.encode("utf8"))
if signer.verify(digest, decodebytes(signature.encode("utf8"))):
return True
return False

def verify(self, data, signature):
if "sign_type" in data:
sign_type = data.pop("sign_type")
# 排序后的字符串
unsigned_items = self.ordered_data(data)
message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
return self._verify(message, signature)

#请求退款接口
def api_alipay_trade_refund(self,refund_amount,out_trade_no=None,trade_no=None,**kwargs):

#构造参数体
biz_content = { "refund_amount":refund_amount}

#传递可选参数
biz_content.update(**kwargs)

#判断使用站外订单还是支付宝订单
if out_trade_no:
biz_content["out_trade_no"] = out_trade_no
if trade_no:
biz_content["trade_no"] = trade_no

#构造支付接口地址
data = self.build_body("alipay.trade.refund",biz_content)

#构造url
url = self.__gateway+"?" + self.sign_data(data)

#请求接口
r = requests.get(url)
html = r.content.decode("utf-8")

return html

在视图定义方法使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
配置路由
path('pay_url/',pay_url),#支付宝跳转视图
path('testpay/',back_url),#会调地址

import time
import os
from django.shortcuts import render,redirect
#导入公共目录变量
from mydjango.settings import BASE_DIR
from django.http import HttpResponse
#导入支付宝支付接口
from mydjango.pay import AliPay
#引入支付宝沙箱秘钥
#应用私钥
app_private_key_string = os.path.join(BASE_DIR,'keys/app_private_2048.txt')
#支付宝公钥
alipay_public_key_string = os.path.join(BASE_DIR,'keys/alipay_public_2048.txt')


#建立支付实例
def get_ali_object():
app_id = '你的沙箱应用ID' #沙箱应用ID
#支付完成后跳转的地址
return_url = 'http://localhost:8000/testpay/'
alipay = AliPay(
appid = app_id,
app_notify_url = return_url,
return_url = return_url,
app_private_key_path = app_private_key_string,
alipay_public_key_path = alipay_public_key_string,
#支付宝公钥,验证支付宝回传消息,不是自己公钥
debug=True,#默认false
)
return alipay

#支付跳转视图
def pay_url(request):
alipay = get_ali_object()
#生成支付的url
query_params = alipay.direct_pay(
subject='test',#商品简单描述
out_trade_no='myorder'+str(time.time()),#订单号,这里使用的是时间戳来做
total_amount= 100.00#交易金额(单元:元 保留两位小数)
)
pay_url = 'https://openapi.alipaydev.com/gateway.do?' + query_params
return redirect(pay_url)
# return HttpResponse('123')

#回调网址
def back_url(request):
return HttpResponse('回调成功')

#回调url
#http://localhost:8080/myorder?charset=utf-8&out_trade_no=4370479805276098561&method=alipay.trade.page.pay.return&total_amount=200.00&sign=LCsKfD3ybvAlhzj1%2BJszACsy%2FeOL18p0A%2FmBIa68ZH2SUNb6163FWP5ScmyrGliBlmEtRVcVPkGASVLiY5l5ESTvFkx7OX3FO9%2FtqPRopSvhnf6jaaPjJt90YcG69Z9XZaqJHlK7LqCocLRKSXb4zxWDpek8QRrpUmkn9gxJgKr64Z7%2FlcjsZMpr1SxGjEhyMZp%2FbgcZfD8X4%2BiUkZThXB1LkKNhcRG5gHZTfoiEj%2FKxOFyH%2BNs4klXFjDTe5217UVMUAE351qfq0%2F%2FCXcZ3aHW52XobDAs12J6eVVtijUr8v2xD%2Bpp5SlgCBhkXt86euH4iVfLn61%2FCOMU7b3HLJQ%3D%3D&trade_no=2020061622001482770501026654&auth_app_id=2016092600603658&version=1.0&app_id=2016092600603658&sign_type=RSA2&seller_id=2088102177418159&timestamp=2020-06-16%2013%3A27%3A16

#回调网址中的参数
# out_trade_no=4370479805276098561 #订单号
# total_amount=200.00 #订单价格
#sign='LCsKfD3ybvAlhzj1%2BJszACsy%2FeOL18p0A%2FmBIa68ZH2SUNb6163FWP5ScmyrGliBlmEtRVcVPkGASVLiY5l5ESTvFkx7OX3FO9%2FtqPRopSvhnf6jaaPjJt90YcG69Z9XZaqJHlK7LqCocLRKSXb4zxWDpek8QRrpUmkn9gxJgKr64Z7%2FlcjsZMpr1SxGjEhyMZp%2FbgcZfD8X4%2BiUkZThXB1LkKNhcRG5gHZTfoiEj%2FKxOFyH%2BNs4klXFjDTe5217UVMUAE351qfq0%2F%2FCXcZ3aHW52XobDAs12J6eVVtijUr8v2xD%2Bpp5SlgCBhkXt86euH4iVfLn61%2FCOMU7b3HLJQ%3D%3D'#签名
# trade_no=2020061622001482770501026654 #支付宝订单号
# auth_app_id=2016092600603658 #应用ID
# version=1.0 #版本
# sign_type='RSA2' #算法
# seller_id=2088102177418159 #支付者ID
# timestamp='2020-06-16%2013%3A27%3A16'#时间戳

在沙箱账号中,有个买家和卖家账号,在使用沙箱做测试支付的时候,使用的是买家账号,账号密码还有登陆密码都有说明,还需要充值买家账号余额,这里的金钱都是虚拟的。这样就可以完成测试支付宝付款了。快去测试一波吧!!

评论





载入天数...载入时分秒...

Blog content follows the Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) License

Use WZH as theme, total visits times