在使用支付宝支付功能开发的阶段, 可以在沙箱环境下进行开发, 开发完成之后, 到线上再进行相关参数的替换即可

一. 登陆支付宝开放平台(https://open.alipay.com/platform/home.htm)

进入沙盒环境:

二. 设置加密方式 RSA 或者RSA2(推荐)

  1. 生成RSA秘钥

    可以使用支付宝提供的生成工具,具体说明见官网说明(https://opendocs.alipay.com/open/291/105971#LDsXr)

    使用工具生成秘钥对

  应用公钥: 需要将公钥填写到RSA2秘钥的设置中

  应用私钥:是生成签名需要使用的

  支付宝公钥: 在设置中点击查看支付宝公钥即可看到

  

  2. 秘钥文件的修改

    在秘钥文件中的内容的头部和尾部加上两行字符串, 注意所有的秘钥都要添加

-----BEGIN PRIVATE KEY-----
# 秘钥内容....
-----END PRIVATE KEY-----

    这样可以方便的直接读取文件

三. 集成支付宝到项目

  基本流程:

1\. 接收商品名称信息、订单金额、订单号
2\. 请求支付宝预付订单创建接口
3\. 根据返回的URL返回给客户端
4\. 用户支付
5\. 用户支付完成之后,客户端会跳转到一个页面(服务器预置页面)
6\. 用户支付完成之后,支付宝会调用回调(通知服务器)

  安装模块

# 需要模块加密方面的模块
pip install pycryptodome

封装类

# __init__.py文件(直接拷贝)
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytes
import json # 支付宝封装(不需要做任何修改)
class AliPay(object):
"""
支付宝支付接口
"""
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.import_key(fp.read()) 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 ordered_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) # 初始化操作
# 设置秘钥公钥的存放路径
app_private_key_path = os.path.join(BASE_DIR, 'alipay/ying_yong_si_yao.txt')
alipay_public_key_path = os.path.join(BASE_DIR, 'alipay/zhi_fu_bao_gong_yao.txt')
# 根据自己申请的进行设置
alipay = AliPay(
appid="2016091800542542", # 设置签约的appid
app_notify_url="http://112.74.55.3/notify/", # 异步支付通知url
app_private_key_path=app_private_key_path, # 设置应用私钥
alipay_public_key_path=alipay_public_key_path, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
debug=True, # 默认False, # 设置是否是沙箱环境,True是沙箱环境
return_url="http://112.74.55.3/result/", # 同步支付通知url,在这个页面可以展示给用户看,只有付款成功后才会跳转
)

  

备注: return_url 和 notify_url的区别
return_url:
如果设置了return_url,买家付款成功后会跳到return_url所在页面;
在这个页面可以展示给用户看,只有付款成功后才会跳转; notify_url:
服务器后台通知,这个页面是程序后台运行的(买家和卖家都看不到);
买家付完款后,支付宝会调用notify_url这个页面所在的页面并把相应的参数传递到这个页面;
这个页面根据支付宝传递过来的参数修改网站订单的状态,更新完订单后需要在页面上;
打印出一个success给支付宝,如果反馈给支付宝的不是success,支付宝会继续调用这个页面;

  

应用 公钥:

-----BEGIN PRIVATE KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5X3ezQUT2Cg5ujqoz+dfEBTGzavJRxG8CsXMzs5ualReWI0i3Itn15rG9mqYQUqIsfte2gAHc3+rNgMR8oEjcVrgY0qcPl/D3rj+/h0vYHl7lT5g93+n7/CVlk9KOhCm217kFV3gAJYusIXk6jWtpFXl2nXq1BlNhDgrBli4dozJ2k99OSUfNndrpuGfAVIOGIG4dsff598k+gb92eXwT151DMrqoV++387vRRnNnnBqbnYldBodBJXNyEsUCaf+CtacJy72tL6IwRVErD2MVuGjMWQ25Y1qWa/kNXI6ElIDljZylpWFDfMySMFkyOQra3RePlda7pDeKLmPwbwHpQIDAQAB
-----END PRIVATE KEY-----

应用私钥:

-----BEGIN PRIVATE KEY-----
MIIEpQIBAAKCAQEA5X3ezQUT2Cg5ujqoz+dfEBTGzavJRxG8CsXMzs5ualReWI0i3Itn15rG9mqYQUqIsfte2gAHc3+rNgMR8oEjcVrgY0qcPl/D3rj+/h0vYHl7lT5g93+n7/CVlk9KOhCm217kFV3gAJYusIXk6jWtpFXl2nXq1BlNhDgrBli4dozJ2k99OSUfNndrpuGfAVIOGIG4dsff598k+gb92eXwT151DMrqoV++387vRRnNnnBqbnYldBodBJXNyEsUCaf+CtacJy72tL6IwRVErD2MVuGjMWQ25Y1qWa/kNXI6ElIDljZylpWFDfMySMFkyOQra3RePlda7pDeKLmPwbwHpQIDAQABAoIBAQDIh24SE+e9L5kRw4QS9we4E4+L1BnywepgN2q5IuSUgNhX5CucLywz14kXdRlJpAlCDHZbYz8fi2Vdst0R3AnOWSxNVrqkPiX3DguynGnzkPON+43bdm6WWNE9IFep2TcT5RzEFt1PZeuyT60xgmoSeQR6GiNx5hI4AKSHzSqSWteL9xd/IUbHrA4YBXhX/oqJdrQr7Ri+380qoHHLiz5gNkXzVGFKrqVwsvVOBGdQ75S+wSTmJJ6hYm9vF4T7FQk8Ar22/22ZFuNLa1IMDXEe8Oh5NVCoXQqMFyhAYf7oN4AzZrBSvLmd85wfQSmvbthmL2JdOynEytYVa7Q2F3zZAoGBAPp6RDO16jEZySrX4T/eKukCD1Cq2g1LAPsq8dxjfdSgNxtz9qt24vuflZu2RbW/VoLZxDZJEIGhY7x0ClhioEwixBCHuPcXLFRd4mvxawzpJBRg9z0Mquf1cret6CBqsML+hgqlu2WwAbgX6hJ3ZJ8Sz3zICoG3K1NgzQkAbsybAoGBAOqNJ/r56jtB42XeGrNRE9bmpOnNDMN56oKiGDIMMe/FDjwYJw/dX7Ih3k0AAGgQWgdq03s+6ji3sI65mcqUrwBf6gSufDWrOvolbKIIfiC1dn/h81HsfkC5y02hTjfmfYg/nCXF5WUsVahrYRgTZL6iHrav2EighyxZCHDlWiC/AoGBAKdkiqvcSTSjPPOq7lgWi6rIu593bt4vX+p7WsOkofU1VV69cv5IJ41tqzgy6gd6ZcBw9FYrIiLfzp2lFzzWPLZlDY7WhWBsVi3TyHvHDXnFXV1ZKCHek2ENgasLR/RSGOtX2hDHjaN5qsxy/vV0YQSGN6/2qD7kQMoqCRyY83M9AoGBAJrvUViVG2e3V1nkBCktRnivdIJIg8TgVMuj/W2Z5qamuYdywOLW7a7CdpDQjnQvUPkTVM1VuuxqUoOFEJTj8FHECda716qwCE5SyFakW4SJudQx0kPsf12MHUKTahK8+3Ez65Z8CdLyHUcaX1HDBcpzVuyAbdNTzta5nTzOE+ILAoGAF0dMOdqnprsr82MudHqjIZMSanfd+QHgARNT0IQVxIFBIsV4PkGmHKU2EZdcB604mZYqAKaCJy+LZIE6VGpgGydRZ98RSK/jaNprge5cm9KPy9nGdfVKBhPkrU3Lkcix0gcvRWC3HVVaYMiZlS1i1tpwgI8z0xtoA9EoLJGxuYc=
-----END PRIVATE KEY-----

支付宝公钥:

-----BEGIN PRIVATE KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtaQiWU7tUcDzqbTT5cWF6PS9jn6sMlpG4wR1YFhUo8TDqW1FI5wi/dfylOqJSS2lV8OOuzMk80Ajq9wbyQ0oB+dmrgcZIwF8bLkHvGyO83SAmmNmZ8bcnlD91EnS2c+vIF02ADpE/NKaX+5gjXj9FMTr5z6cqrpfjxWYB7FCp77fd1hd6TbzkMaW70RzBkWGTVMG91p7uZexVKkURPl5Sb8KRnXSmTkjTTWBFZOsARFVu7nsbMjd+q3RYni3BvhfKyZIW/PtQ9HUrX3tHbGThdj2D4qgO3mWB51IdH0gM9OOTyFYvm9TMJGeJ6KdeELlGLNVGhRAbK4NJjPlnuVd2wIDAQAB
-----END PRIVATE KEY-----

支付示例:

# 定义资源
class Pay(Resource):
def post(self):
# 获取订单号,根据订单生成 支付订单
# 支付订单包括: 订单号、支付金额、订单名称 # 传递参数执行支付类里的direct_pay方法,返回签名后的支付参数,
url = alipay.direct_pay(
subject="测试订单", # 订单名称
# 订单号生成,一般是当前时间(精确到秒)+用户ID+随机数
out_trade_no="201810021221", # 订单号
total_amount=100, # 支付金额
return_url="http://112.74.55.3/result/" # 支付成功后,跳转url 【客户端显示】
) # 将前面后的支付参数,拼接到支付网关
# 注意:下面支付网关是沙箱环境,最终进行签名后组合成支付宝的url请求
re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url) # 返回的是支付宝的支付地址
return {'re_url': re_url} # 添加资源
api.add_resource(Pay, '/paytest/') # 支付接口

  

支付宝同步数据:

# 支付宝返回的数据
data = {
'seller_id': '2088102176233911',
'trade_no': '2018101822001438720500654194', # 订单号
'timestamp': '2018-10-18 00:12:54',
'app_id': '2016091800542542',
'version': '1.0',
'sign_type': 'RSA2',
'out_trade_no': '6823789339978248',
'auth_app_id': '2016091800542542',
'total_amount': '123.00',
'charset': 'utf-8',
'method': 'alipay.trade.page.pay.return'
'sign': 'cjok55ELAfbGc9RfwsS93pplaFNUIv0hAsfzbklDU+5sdnq0lc9K1a+IRO8MJZpwCX9OjBLXqY64LEa2cM5hv0bly2HnEmbNTta8e15VdvXFH//zMWT05HeNmXu2+H3Kq2RzQbFs2LIdFD2HmYDnbkwhTyAxnhQWEn7yZdAeD/7vNjGoREW2Xbh3aV5ukSFBihzwTGJNMNxyKei6KxQwJRJKDyV0fdZyH6i39xoyp8aMfQGZqRC9HbKKBW6BsFg/At1hVsMJQ4Ib/6jK2NMNMckUIf1gXLrY4Gv/LaqVSYuZpwNQoEwgHYHiC9KUa0BhsgAlJDEpARliLnvyUUOJKA=='
}

支付宝异步数据:

# 支付宝返回的数据
data = {
"subject": "测试订单",
"gmt_payment": "2016-11-16 11:42:19",
"charset": "utf-8",
"seller_id": "xxxx",
"trade_status": "TRADE_SUCCESS",
"buyer_id": "xxxx",
"auth_app_id": "xxxx",
"buyer_pay_amount": "0.01",
"version": "1.0",
"gmt_create": "2016-11-16 11:42:18",
"trade_no": "xxxx", # 订单号
"fund_bill_list": "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]",
"app_id": "xxxx",
"notify_time": "2016-11-16 11:42:19",
"point_amount": "0.00",
"total_amount": "0.01",
"notify_type": "trade_status_sync",
"out_trade_no": "xxxx",
"buyer_logon_id": "xxxx",
"notify_id": "xxxx",
"seller_email": "xxxx",
"receipt_amount": "0.01",
"invoice_amount": "0.01",
"sign": "xxx"
}

注意点:

  1. 测试的时候, 使用沙盒环境的支付宝

  平台提供了沙盒账号,进行登陆与支付的时候使用

  2. 参数说明

appid :2016091700535495(填写沙箱应用的appid)
return_url: 对于PC网站支付的交易,在用户支付完成之后,支付宝会根据API中商户传入的return_url参数,通过GET请求的形式将部分支付结果参数通知到商户系统, 即同步返回地址,即支付成功跳转的页面url。同步通知详情
sign 签名字段,最重要的字段,后面会讲,详见签名
notify_url: 对于PC网站支付的交易,在用户支付完成之后,支付宝会根据API中商户传入的notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统。异步通知详情
biz_content:除公共参数以外的其他必要参数 请求参数这些字段是最后放入公共字段里的biz_content,着重关注必填项

  3. 生成签名与签名验证

import json

from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import urlparse, parse_qs, quote_plus class Alipay(object):
def __init__(self, app_id, app_private_key_path, alipay_public_key_path, debug=True, return_url=None, notify_url=None):
self.app_id = app_id
self.debug = debug
self.return_url = return_url
self.notify_url = notify_url with open(app_private_key_path) as fp:
self.app_private_key = RSA.importKey(fp.read())
with open(alipay_public_key_path) as fp:
self.alipay_public_key = RSA.importKey(fp.read()) if debug:
self.__gateway = "https://openapi.alipaydev.com/gateway.do"
else:
self.__gateway = "https://openapi.alipay.com/gateway.do" def build_url(self, biz_content):
"""
:param biz_content: 请求参数部分
:return: 完整的访问地址url字符串
"""
# 初始化必填公共字段,sign除外
data = {
"app_id": self.app_id,
"method": "alipay.trade.page.pay",
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"biz_content": biz_content
}
if self.notify_url:
data["notify_url"] = self.notify_url
if self.return_url:
data["return_url"] = self.return_url # 对待签名字符串进行RSA签名
sign_str = self.get_request_url_str(data, flag=False)
sign = self.rsa_sign(sign_str.encode("utf-8")) # 将签好名的sign字段拼接到请求字符串最后,字符串需对斜线进行编码
request_url_str = self.get_request_url_str(data)
request_url_str += "&sign={}".format(quote_plus(sign))
print(self.__gateway + '?' + request_url_str)
return self.__gateway + '?' + request_url_str def translate_url(self, returl_url):
"""
:param returl_url:返回字符串
:return: 解析出请求参数字符串及签名
"""
o = urlparse(return_url)
query = parse_qs(o.query)
processed_query = {} ali_sign = query.pop("sign")[0] if "sign" in query else None if "sign_type" in query:
sign_type = query.pop("sign_type")[0]
for key, value in query.items():
processed_query[key] = value[0]
request_url_str = self.get_request_url_str(processed_query, flag=False).encode("utf-8")
# 将解析后的request_url_str字符串和签名参数拼接成元祖
data = ([request_url_str, ali_sign])
return data def get_biz_content(self, out_trade_no, total_amount, subject, **kwargs):
"""
获取请求参数
"""
biz_content = {
"out_trade_no": out_trade_no,
"product_code": "FAST_INSTANT_TRADE_PAY",
"total_amount": total_amount,
"subject": subject,
}
biz_content.update(kwargs)
return biz_content def get_request_url_str(self, data, flag=True):
"""
:param data: 获取的字典型请求参数
:param flag: 是否对字典的值进行编码斜线
:return:排好序并用&进行拼接的url字符串
"""
#对键值为字典的转化为str
for k, v in data.items():
if isinstance(v, dict):
data[k] = json.dumps(v)
# 按key值字母升序排序为列表,方便拼接
data_lst = sorted([(k, v) for k, v in data.items()])
if flag:
request_url_str = "&".join(["{k}={v}".format(k=k, v=quote_plus(v)) for k, v in data_lst])
else:
request_url_str = "&".join(["{k}={v}".format(k=k, v=v) for k, v in data_lst])
return request_url_str def rsa_sign(self, data):
"""
利用商户私钥对待签名字符串进行签名
:param data: 待签名data,格式bytes
:return: 生成的签名字符串
"""
private_key = self.app_private_key
hash_obj = SHA256.new(data)
signer = PKCS1_v1_5.new(private_key)
signature = signer.sign(hash_obj)
sign = b64encode(signature).decode("utf-8")
return sign def rsa_verify(self, raw_data, signature):
"""
使用RSA2的验签方法,通过签名字符串、签名参数(经过base64解码)及支付宝公钥验证签名,
根据返回结果判定是否验签通过
:param raw_data: 原签名字符串data,格式bytes
:param signature: 签名参数
:return: 验签是否通过
"""
public_key = self.alipay_public_key
hash_obj = SHA256.new(raw_data)
verifier = PKCS1_v1_5.new(public_key) return verifier.verify(hash_obj, b64decode(signature.encode("utf-8"))) if __name__ == "__main__":
alipay = Alipay(
app_id="2016091700535495",
return_url="http://101.200.32.20:8000/",
notify_url="http://projectsedus.com/",
app_private_key_path="../trade/keys/private_2048.txt",
alipay_public_key_path="../trade/keys/alipay_keys_2048.txt",
)
content = alipay.get_biz_content(out_trade_no="201802021232", total_amount=1, subject="测试支付")
alipay.build_url(content) # 根据return_url获取请求参数
return_url = "http://101.200.32.20:8000/?charset=utf-8&out_trade_no=201702021230&method=alipay.trade.page.pay.return&total_amount=1.00&sign=gvXy%2FXOSOUQupNTn%2Fi%2BdkpqqcDc0Ia8R5lZ2kQRl5UcVb6w83pJqadDPzjdCTLq7%2F4aoIEHhAR6%2FOZwXmsEGWGd2DNynjiGF2mzIpKjDIaGLhdlP9DMIVy%2BIuCfLB7tHC9n1%2BPYoH1YYVWIqO%2B5FLcTh77ucwP66Glq5gFBKpD0b6fiPYlAjxO%2FAIEiyRxSaZS3fj%2BBOhB%2Fo31rjMLa5EOHgvdDeP8OTa01VVJ3wAMBDHyGslj5cShZQwdALyuxjGTFOb0PHFiWEjS828j7ZiTkWiODZ2QFClLE9NHwR6VrlnT0Ttss9Hfu8zwIBMsK3SWt9f32TnmC2wq7hkvMsyg%3D%3D&trade_no=2018082021001004950200556565&auth_app_id=2016091700535495&version=1.0&app_id=2016091700535495&sign_type=RSA2&seller_id=2088102176097894&timestamp=2018-08-20+23%3A23%3A12"
data = alipay.translate_url(return_url)
print(alipay.rsa_verify(data[0], data[1]))

 

遇到的问题:

  1. 使用支付提供的验证签名工具一直都是签名失败, 后台发现是它工具版本问题, 导致不能验证成功

    下载了1.4版本就可以成功了, 最新版提供了在线工具:https://miniu.alipay.com/keytool/

  验证过程:

一、验签准备
1.原始报文:
【gmt_create=2020-03-25 10:59:32&charset=utf-8&gmt_payment=2020-03-25 10:59:38&notify_time=2020-03-25 10:59:38&subject=仙玉小袋&sign=zs+snU7B3l4Cnec/JWBcXWkFUNWrW1ttEeMZI4X2mtuSNQ9LL9Mri3b6QK0xTc/KMs/Cafk0Ln7iRKQZfnuBvvuaOwVxSgjuWT0ygGktDok0HITE2wKeT8j4SNX4ScIGHLqHXkMojXIZxE6bsfD9kjUb356aFItinf3vURu3FuPSkbJR1KZXDm41hz2rQ9o6Sc3Xs2cr7AbCSVgyGjv5c6G6OiqaXcdgM+FxHtxkhfqB/3awRjXMGmLmWr2m5VyFIfNMOuNCdRN7fNkUBIX3h35KI6av/x6BDYKwTW2zrJHVy91C0h3mrVoDNuRrJ4fPMW2ZH88j7Q3exmPTP0gqMA==&buyer_id=2088002582656381&body=仙玉小袋&invoice_amount=0.01&version=1.0&notify_id=2020032500222105938056380529774436&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&notify_type=trade_status_sync&out_trade_no=TEST171&total_amount=0.01&trade_status=TRADE_SUCCESS&trade_no=2020032522001456380542497258&auth_app_id=2021001144680325&receipt_amount=0.01&point_amount=0.00&buyer_pay_amount=0.01&app_id=2021001144680325&sign_type=RSA2&seller_id=2088031940831575】 2.验签公钥:
【MIIBIjANBgktf9owIDAQAB】 3.从报文取出签名值sign:
【zs+snU7B3l4Cnec/JWBcXWkFUNWrW1ttEeMZI4X2mtuSNQ9LL9Mri3b6QK0xTc/KMs/Cafk0Ln7iRKQZfnuBvvuaOwVxSgjuWT0ygGktDok0HITE2wKeT8j4SNX4ScIGHLqHXkMojXIZxE6bsfD9kjUb356aFItinf3vURu3FuPSkbJR1KZXDm41hz2rQ9o6Sc3Xs2cr7AbCSVgyGjv5c6G6OiqaXcdgM+FxHtxkhfqB/3awRjXMGmLmWr2m5VyFIfNMOuNCdRN7fNkUBIX3h35KI6av/x6BDYKwTW2zrJHVy91C0h3mrVoDNuRrJ4fPMW2ZH88j7Q3exmPTP0gqMA==】 二、组成待验签串:
1.剔除空值参数:
【gmt_create=2020-03-25 10:59:32&charset=utf-8&gmt_payment=2020-03-25 10:59:38&notify_time=2020-03-25 10:59:38&subject=仙玉小袋&sign=zs+snU7B3l4Cnec/JWBcXWkFUNWrW1ttEeMZI4X2mtuSNQ9LL9Mri3b6QK0xTc/KMs/Cafk0Ln7iRKQZfnuBvvuaOwVxSgjuWT0ygGktDok0HITE2wKeT8j4SNX4ScIGHLqHXkMojXIZxE6bsfD9kjUb356aFItinf3vURu3FuPSkbJR1KZXDm41hz2rQ9o6Sc3Xs2cr7AbCSVgyGjv5c6G6OiqaXcdgM+FxHtxkhfqB/3awRjXMGmLmWr2m5VyFIfNMOuNCdRN7fNkUBIX3h35KI6av/x6BDYKwTW2zrJHVy91C0h3mrVoDNuRrJ4fPMW2ZH88j7Q3exmPTP0gqMA==&buyer_id=2088002582656381&body=仙玉小袋&invoice_amount=0.01&version=1.0&notify_id=2020032500222105938056380529774436&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&notify_type=trade_status_sync&out_trade_no=TEST171&total_amount=0.01&trade_status=TRADE_SUCCESS&trade_no=2020032522001456380542497258&auth_app_id=2021001144680325&receipt_amount=0.01&point_amount=0.00&buyer_pay_amount=0.01&app_id=2021001144680325&sign_type=RSA2&seller_id=2088031940831575】 2.剔除sign、sign_type参数:
【gmt_create=2020-03-25 10:59:32&charset=utf-8&gmt_payment=2020-03-25 10:59:38&notify_time=2020-03-25 10:59:38&subject=仙玉小袋&buyer_id=2088002582656381&body=仙玉小袋&invoice_amount=0.01&version=1.0&notify_id=2020032500222105938056380529774436&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&notify_type=trade_status_sync&out_trade_no=TEST171&total_amount=0.01&trade_status=TRADE_SUCCESS&trade_no=2020032522001456380542497258&auth_app_id=2021001144680325&receipt_amount=0.01&point_amount=0.00&buyer_pay_amount=0.01&app_id=2021001144680325&seller_id=2088031940831575】 3、排序:
【app_id=2021001144680325&auth_app_id=2021001144680325&body=仙玉小袋&buyer_id=2088002582656381&buyer_pay_amount=0.01&charset=utf-8&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&gmt_create=2020-03-25 10:59:32&gmt_payment=2020-03-25 10:59:38&invoice_amount=0.01&notify_id=2020032500222105938056380529774436&notify_time=2020-03-25 10:59:38&notify_type=trade_status_sync&out_trade_no=TEST171&point_amount=0.00&receipt_amount=0.01&seller_id=2088031940831575&subject=仙玉小袋&total_amount=0.01&trade_no=2020032522001456380542497258&trade_status=TRADE_SUCCESS&version=1.0】 三、验签结果:
【验签成功】

  校验demo:

from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
import Crypto.Hash.SHA512
from Crypto.Hash import SHA, SHA256 import base64 def rsa2_verify(sign, plaintext, keypath):
print('*' * 100)
print('sign =', sign)
with open(keypath) as f:
key = f.read()
print('plaintext =', plaintext)
hash_value = SHA256.new(plaintext.encode('utf-8'))
print('hash_value =', hash_value)
verifier = PKCS1_v1_5.new(RSA.importKey(key))
# 验证,通过返回true,失败返回false
print('*' * 100)
return verifier.verify(hash_value, base64.b64decode(sign)) if __name__ == '__main__':
message = 'app_id=2021001144680325&auth_app_id=2021001144680325&trade_status=TRADE_SUCCESS&version=1.0' publickeyPath = r"H:\alipay\xn\alipay_public.txt" # alipay的公钥 不是app公钥
result = rsa2_verify(signature, message, publickeyPath) print('result =', result)

支付宝支付功能接入(PC)的更多相关文章

  1. django中使用事务以及接入支付宝支付功能

    之前一直想记录一下在项目中使用到的事务以及支付宝支付功能,自己一直犯懒没有完,趁今天有点兴致,在这记录一下. 商城项目必备的就是支付订单的功能,所以就会涉及到订单的保存以及支付接口的引入.先来看看订单 ...

  2. 支付宝支付功能(使用支付宝sdk)

    1.准备参数        新建一个公共参数配置类NewAlipayconfig (可将参数存放到config配置文件中读取)          public class NewAlipayconfi ...

  3. laravel实现支付宝支付功能

    起因 前段时间因为项目中需要实现支付宝手机网站支付功能,所以写下这篇文章以作记录,不足之处,欢迎指教. 后端框架:Laravel 5.5 业务功能 适用于商家在移动端网页应用中集成支付宝支付功能.商家 ...

  4. SSM 实现支付宝支付功能(图文详解+完整代码)

    阅读本文大概需要 4 分钟. 前言 本教程详细介绍了如何使用ssm框架实现支付宝支付功能.本文章分为两大部分,分别是「支付宝测试环境代码测试」和「将支付宝支付整合到ssm框架」,详细的代码和图文解释, ...

  5. ThinkPHP接入支付宝支付功能

    最近做系统,需要实现在线支付功能,毫不犹豫,选择的是支付宝的接口支付功能.这里我用的是即时到帐的接口,具体实现的步骤如下: 一.下载支付宝接口包 下载地址:https://b.alipay.com/o ...

  6. ThinkPHP5.0 实现 app支付宝支付功能

    前几天做项目,要求要用到支付宝接口,第一次做,弄了好几天 各种坑啊,简单写一下我做支付宝支付的过程,希望对也是第一次做支付宝支付的童鞋有帮助, 不懂的可以先去支付平台看一下支付宝支付的文档,我是下的d ...

  7. mui实现支付宝支付功能

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>H ...

  8. ASP.NET Core Web 支付功能接入 支付宝-电脑网页支付篇

    这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入支付宝-电脑网页支付接口及同步跳转及异步通知功能. 开发环境:Win 10 x64.VS2017 15.6.4..NET ...

  9. 【转载】ASP.NET Core Web 支付功能接入 支付宝-电脑网页支付篇

    转自:http://www.cnblogs.com/essenroc/p/8627775.html 这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入支付宝-电脑网页支付 ...

  10. thinkphp3.2接入支付宝支付接口(PC端)

    下载支付宝接口包    点击这里        提取密码:aryp 整个接口核心类文件 alipay.config.php是相关参数的配置文件 alipayapi.php 是支付宝接口入口文件 not ...

随机推荐

  1. 即构音视频 Express Flutter SDK 全面支持空安全

    Flutter 是一套移动 UI 框架,可以快速在 iOS.Android 上构建高质量的原生用户界面.作为其官方语言 Dart 是类型安全的,当开发者获取变量的时候,编译器可以保证变量的类型,但类型 ...

  2. Redis 入门 - C#|.NET Core客户端库六种选择

    经过前面的Redis基础学习,今天正式进入编码阶段了,进入编码阶段我们又同样面临一道多选题,选择什么客户端库?要是有选择困难症的又要头疼了.不过别担心我先头疼,今天就给大家介绍6款.NET系Redis ...

  3. 小tips:HTML5的ruby标签实现给汉字加拼音、details标签实现折叠面板、原生进度条progress和度量meter

    ruby标签实现给汉字加拼音 ruby 元素由一个或多个字符(需要一个解释/发音)和一个提供该信息的 rt 元素组成,还包括可选的 rp 元素,定义当浏览器不支持 "ruby" 元 ...

  4. Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数

    title: Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数 date: 2024/9/14 updated: 2024/9/14 author: cmdragon excerpt: 通 ...

  5. 以太坊Rollup方案之 arbitrum(2)

    上一期简单介绍了一下rollup的一些基本内容以及aritrun交易的执行流程,这一期将介绍一下aritrum的核心技术 -- 交互式单步证明 这一期主要涉及到的是arbitrum的验证节点 arbi ...

  6. 1Before You Install Flask...Watch This! Flask Fridays #1

    flask官网: https://flask.github.net.cn/ git官网: https://git-scm.com/ 建立文件: 建立虚拟环境.激活: source virt/Scrip ...

  7. Epic Games Launcher 提示 应用程序无法正常启动(0xc000007b)

    事件起因: 在给某同事安装Epic Games Launcher报错, 提示 应用程序无法正常启动(0xc000007b) 解决办法: 用DirectX修复工具扫一下,修复一下C++插件,一般是由于 ...

  8. PasteForm最佳CRUD实践,实际案例PasteTemplate详解之3000问(二)

    作为"贴代码"力推的一个CRUD实践项目PasteTemplate,在对现有的3个项目进行实战后效果非常舒服!下面就针对PasteForm为啥我愿称为最佳CRUD做一些回答: 哪里 ...

  9. iOS之动画(transform和UIView动画)学习

    1.transform 形变 这个是UIView的属性,继承UIView的控件都具有这个属性 UIImageView *imageview=[[UIImageView alloc]init]; ima ...

  10. Linux环境下的mysql安装

    MySQL8.0.26-Linux版安装 1.准备一台Linux服务器 云服务器或者虚拟机都可以; Linux的版本为 Centos7; 2.下载Linux版MySQL安装包 https://down ...