微信API-v3版本签名Python版本的资料相对比较少,最近完成踩坑。
需要配置的依赖库:
requests = "*"
pycryptodome = "*"
cryptodome = "*"
pyopenssl = "*"
pycryptodomex = "*"
m2crypto = "*"
部分依赖库导入速度比较慢, 可以更换源地址或者多尝试导入几次。
动态获取证书文件地址
import os
basedir = os.path.abspath(os.path.dirname(os.path.dirname('manage.py')))
KEY_PATH = os.path.join(basedir, "static", "apiclient_key.pem")
CERT_PATH = os.path.join(basedir, "static", "apiclient_cert.pem")
动态生成32位随机字符
def nonce_str(length=32):
char = string.ascii_letters + string.digits
return "".join(random.choice(char) for _ in range(length))
加签转义
@staticmethod
def b(s):
return s.encode("utf-8")
生成时间搓
def get_timestamp():
import time
return str(int(time.time()))
转json
def to_json(kwargs):
import json
return json.dumps(kwargs, separators=(',', ':'))
apiV3签名
def sign_v3(method, url, timestamp, nonceStr, body):
message = method + "\n" + url + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n"
signer = PKCS1_v1_5.new(RSA.importKey(open(KEY_PATH).read()))
signature = signer.sign(SHA256.new(Utils.b(message)))
sign = encodebytes(signature).decode("utf8").replace("\n", "")
return sign
拼接请求头
def authorization(sign, nonceStr, timestamp):
"""
拼接api版本中请求头的authorization的值
"""
return 'WECHATPAY2-SHA256-RSA2048 mchid="{michid}",nonce_str="{nonce_str}",signature="{signature}",timestamp="{timestamp}",serial_no="{serial_no}"'.format(michid=mch_id, nonce_str=nonceStr, signature=sign, timestamp=timestamp, serial_no=serial_No)
mch_id:商户号
nonceStr:随机字符串
sign:签名字符串
timestamp:时间搓
serial_No:证书序列号,可以直接使用证书解析工具读取。
发起请求
def requests_wx3(url, data, authorization, method='POST', ssl=False, key_path="", cert_path=""):
"""
apiV3 版本的微信支付请求
"""
headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': authorization}
response = ''
try:
if method == 'POST':
if ssl:
response = requests.post(url, data=Utils.to_json(data), headers=headers, cert=(cert_path, key_path))
else:
response = requests.post(url, data=Utils.to_json(data))
if method == 'GET':
if ssl:
response = requests.get(url, data=Utils.to_json(data), cert=(cert_path, key_path))
else:
response = requests.get(url, data=Utils.to_json(data))
except requests.exceptions.ConnectionError as e:
traceback.print_exc()
from pyexpat import ExpatError
try:
return eval(str(response.content, encoding="utf-8"))
except ExpatError:
return {}
Pyhton版本的API-v3的签名大概如此,官方也没有Python版本的SDK和具体示例,后台开发使用Python语言的小伙伴可以参考。
补充说明:
构造签名字符串的时候,body为空的接口,部分需要传空字符串,部分需要传空字典,签名报错的小伙伴可以都尝试一下
对接过程中有问题可加群:759898174