微信V3支付版本中,如何获取正确的签名方法?

2026-05-05 21:241阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1560个文字,预计阅读时间需要7分钟。

微信V3支付版本中,如何获取正确的签名方法?

问题背景:最近接入微信支付,但微信官方并未提供Python版本的SDK,因此只能根据文档手动实现。以下记录微信支付的整体流程、遇到的问题及最终实现。

微信支付流程:

1. 统一下单:调用微信统一下单接口生成预支付交易会话标识。

2.前端跳转:将预支付交易会话标识发送到前端,引导用户跳转到微信支付页面。

3.支付结果通知:微信支付完成后,微信会发送支付结果通知到服务器。

4.查询订单:服务器可调用微信支付查询订单接口,确认支付状态。

遇到的问题:

1. SDK缺失:由于没有Python版本的SDK,需要手动解析微信返回的XML数据。

2.签名验证:微信支付需要验证签名,确保数据安全。

解决方案:

1. 解析XML:使用Python的xml.etree.ElementTree库解析微信返回的XML数据。

2.签名验证:根据微信文档提供的签名算法进行验证。

具体实现:

python

import xml.etree.ElementTree as ET

def parse_xml(xml_data): root=ET.fromstring(xml_data) return {child.tag: child.text for child in root}

def verify_signature(data, key): # 根据微信文档提供的签名算法进行验证 pass

示例xml_data=100100data=parse_xml(xml_data)print(data)

总结:

通过手动解析XML数据和验证签名,成功实现了微信支付功能。虽然过程较为繁琐,但最终达到了预期效果。

微信V3支付版本中,如何获取正确的签名方法?

问题背景

最近接入微信支付,微信官方并没有提供Python版的服务端SDK,因而只能根据文档手动实现一版,这里记录一下微信支付的整体流程、踩坑过程与最终具体实现。

微信支付APP下单流程

根据微信官方文档: pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_5_2.shtml
下单流程如下:

和支付宝不同,微信多了一个预付单的概念,这里把APP下单实际分为四大部分,其中包含请求微信后端需要的首次签名和需要返回给APP的二次支付信息签名--这里踩一个小坑,流程图中并没把第二次签名支付信息需要返回给APP的步骤画出来(即下面的步骤6.5),因而一开始误以为只需要返回prepay_id给客户端,导致校验失败。
一. 对应步骤1~4,APP 请求业务后端,业务后台进行V3签名后,请求微信后端生成预付单prepay_id
二. 对应步骤5~6.5,业务后端收到微信后端返回prepay_id,将支付相关参数打包进行二次签名后返回给APP,这里相比流程图多了一个6.5--即业务后端返回签名支付信息到APP
三. 对应步骤7~18,APP收到业务后端返回签名支付信息后调起SDK发起支付请求,收到同步消息结果通知
四. 对应步骤19~22,APP查询业务后端,业务后端通过回调通知或直接查询微信后端返回最终支付结果

代码实现 首次签名逻辑

第一次请求生成预付单号的签名文档为:pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml, 共5个部分参与签名,其组成格式为:

HTTP请求方法\nURL\n请求时间戳\n请求随机串\n请求报文主体\n

对应签名代码:

class WechatPayDALBase(object): def __init__(self, mch_appid, mchid, v3key, serial_no, client_key): self.mch_appid = mch_appid self.mchid = mchid self.v3key = v3key # serial_no可通过openssl直接获取, 例: openssl x509 -in 1900009191_20180326_cert.pem -noout -serial self.serial_no = serial_no with open(client_key, 'r') as ifile: pkey = RSA.importKey(ifile.read()) self.signer = pkcs1_15.new(pkey) def compute_sign_v3(self, method, url, body): ''' V3签名逻辑 ''' ts = int(time.time()) nonce = self.generate_nonce() uparts= parse_url(url) ustr = uparts.path + ('?{}'.format(uparts.query) if uparts.query else '') content = '{}\n{}\n{}\n{}\n{}\n'.format(method, ustr, ts, nonce, body) digest = SHA256.new(content.encode('utf-8')) sign_v = base64.b64encode(self.signer.sign(digest)).decode('utf-8') sign_str = 'serial_no="{}",mchid="{}",timestamp="{}",nonce_str="{}",signature="{}"'.format( self.serial_no, self.mchid, ts, nonce, sign_v) return sign_str def make_headers_v3(self, url, headers=None, body='', method='GET'): ''' 微信支付V3版本签名header生成函数 ''' if not headers: headers = {} headers['Accept'] = 'application/json' sign = self.compute_sign_v3(method, url, body) auth_info = 'WECHATPAY2-SHA256-RSA2048 {}'.format(sign) headers['Authorization'] = auth_info return headers def generate_nonce(self): rnd = int(time.time()) + random.randint(100000, 1000000) nonce = hashlib.md5(str(rnd).encode()).hexdigest()[:16] return nonce 二次签名逻辑

由业务后端返回给APP的二次签名信息文档为:pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
共4个部分参与签名,其组成格式为:

应用id\n时间戳\n随机字符串\n预支付交易会话ID\n

返回签名支付信息的对应代码:

def get_pay_sign_info(self, prepay_id): ts = int(time.time()) nonce = self.generate_nonce() content = '{}\n{}\n{}\n{}\n'.format(self.mch_appid, ts, nonce, prepay_id) digest = SHA256.new(content.encode('utf-8')) sign_v = base64.b64encode(self.signer.sign(digest)).decode('utf-8') return { 'appid': self.mch_appid, 'partnerid': self.mchid, 'timestamp': str(ts), 'noncestr': nonce, 'prepay_id': prepay_id, 'package': 'Sign=WXPay', 'sign': sign_v, } 业务后端查询订单详情

文档地址:pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_2.shtml
代码如下:

def query_order(self, out_trade_no): ''' 查询指定订单信息 ''' url = f'api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}?mchid={self.mchid}' headers = self.make_headers_v3(url) rsp = requests.get(url, headers=headers) pay_logger.info('out_trade_no:{}, rsp:{}|{}'.format(out_trade_no, rsp.status_code, rsp.text)) rdct = rsp.json() return rdct 业务后端调用APP下单API

文档地址:pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
代码如下:

def create_order_info(self, data, callback_url): ''' 创建微信预支付订单, 注意包含两次签名过程: 首次签名用于请求微信后端获取prepay_id 二次签名信息返回客户端用于调起SDK支付 ''' url = 'api.mch.weixin.qq.com/v3/pay/transactions/app' ndt = datetime.now() out_trade_no = self.generate_partner_trade_no(ndt) data = { 'mchid': self.mchid, 'out_trade_no': out_trade_no, 'appid': self.mch_appid, 'description': data['subject'], 'notify_url': callback_url, 'amount': { 'currency': 'CNY', 'total': int(data['price']), }, 'time_expire': (ndt + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S+08:00') } jdata = json.dumps(data, separators=[',', ':']) headers = {'Content-Type': 'application/json'} # 第一次签名, 直接请求微信后端 headers = self.make_headers_v3(url, headers=headers, body=jdata, method='POST') rsp = requests.post(url, headers=headers, data=jdata) pay_logger.info('rsp:{}|{}'.format(rsp.status_code, rsp.text)) rdct = rsp.json() # 第二次签名, 返回给客户端调用 sign_info = self.get_pay_sign_info(rdct['prepay_id']) return sign_info 源码地址

试水代码开源,把相关代码分享在了github:github.com/liuzhi67/wechat-pay-python

转载请注明出处,原文地址:www.cnblogs.com/AcAc-t/p/wechat_pay_by_python.html

签名:拥抱开源,拥抱自由

本文共计1560个文字,预计阅读时间需要7分钟。

微信V3支付版本中,如何获取正确的签名方法?

问题背景:最近接入微信支付,但微信官方并未提供Python版本的SDK,因此只能根据文档手动实现。以下记录微信支付的整体流程、遇到的问题及最终实现。

微信支付流程:

1. 统一下单:调用微信统一下单接口生成预支付交易会话标识。

2.前端跳转:将预支付交易会话标识发送到前端,引导用户跳转到微信支付页面。

3.支付结果通知:微信支付完成后,微信会发送支付结果通知到服务器。

4.查询订单:服务器可调用微信支付查询订单接口,确认支付状态。

遇到的问题:

1. SDK缺失:由于没有Python版本的SDK,需要手动解析微信返回的XML数据。

2.签名验证:微信支付需要验证签名,确保数据安全。

解决方案:

1. 解析XML:使用Python的xml.etree.ElementTree库解析微信返回的XML数据。

2.签名验证:根据微信文档提供的签名算法进行验证。

具体实现:

python

import xml.etree.ElementTree as ET

def parse_xml(xml_data): root=ET.fromstring(xml_data) return {child.tag: child.text for child in root}

def verify_signature(data, key): # 根据微信文档提供的签名算法进行验证 pass

示例xml_data=100100data=parse_xml(xml_data)print(data)

总结:

通过手动解析XML数据和验证签名,成功实现了微信支付功能。虽然过程较为繁琐,但最终达到了预期效果。

微信V3支付版本中,如何获取正确的签名方法?

问题背景

最近接入微信支付,微信官方并没有提供Python版的服务端SDK,因而只能根据文档手动实现一版,这里记录一下微信支付的整体流程、踩坑过程与最终具体实现。

微信支付APP下单流程

根据微信官方文档: pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_5_2.shtml
下单流程如下:

和支付宝不同,微信多了一个预付单的概念,这里把APP下单实际分为四大部分,其中包含请求微信后端需要的首次签名和需要返回给APP的二次支付信息签名--这里踩一个小坑,流程图中并没把第二次签名支付信息需要返回给APP的步骤画出来(即下面的步骤6.5),因而一开始误以为只需要返回prepay_id给客户端,导致校验失败。
一. 对应步骤1~4,APP 请求业务后端,业务后台进行V3签名后,请求微信后端生成预付单prepay_id
二. 对应步骤5~6.5,业务后端收到微信后端返回prepay_id,将支付相关参数打包进行二次签名后返回给APP,这里相比流程图多了一个6.5--即业务后端返回签名支付信息到APP
三. 对应步骤7~18,APP收到业务后端返回签名支付信息后调起SDK发起支付请求,收到同步消息结果通知
四. 对应步骤19~22,APP查询业务后端,业务后端通过回调通知或直接查询微信后端返回最终支付结果

代码实现 首次签名逻辑

第一次请求生成预付单号的签名文档为:pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml, 共5个部分参与签名,其组成格式为:

HTTP请求方法\nURL\n请求时间戳\n请求随机串\n请求报文主体\n

对应签名代码:

class WechatPayDALBase(object): def __init__(self, mch_appid, mchid, v3key, serial_no, client_key): self.mch_appid = mch_appid self.mchid = mchid self.v3key = v3key # serial_no可通过openssl直接获取, 例: openssl x509 -in 1900009191_20180326_cert.pem -noout -serial self.serial_no = serial_no with open(client_key, 'r') as ifile: pkey = RSA.importKey(ifile.read()) self.signer = pkcs1_15.new(pkey) def compute_sign_v3(self, method, url, body): ''' V3签名逻辑 ''' ts = int(time.time()) nonce = self.generate_nonce() uparts= parse_url(url) ustr = uparts.path + ('?{}'.format(uparts.query) if uparts.query else '') content = '{}\n{}\n{}\n{}\n{}\n'.format(method, ustr, ts, nonce, body) digest = SHA256.new(content.encode('utf-8')) sign_v = base64.b64encode(self.signer.sign(digest)).decode('utf-8') sign_str = 'serial_no="{}",mchid="{}",timestamp="{}",nonce_str="{}",signature="{}"'.format( self.serial_no, self.mchid, ts, nonce, sign_v) return sign_str def make_headers_v3(self, url, headers=None, body='', method='GET'): ''' 微信支付V3版本签名header生成函数 ''' if not headers: headers = {} headers['Accept'] = 'application/json' sign = self.compute_sign_v3(method, url, body) auth_info = 'WECHATPAY2-SHA256-RSA2048 {}'.format(sign) headers['Authorization'] = auth_info return headers def generate_nonce(self): rnd = int(time.time()) + random.randint(100000, 1000000) nonce = hashlib.md5(str(rnd).encode()).hexdigest()[:16] return nonce 二次签名逻辑

由业务后端返回给APP的二次签名信息文档为:pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
共4个部分参与签名,其组成格式为:

应用id\n时间戳\n随机字符串\n预支付交易会话ID\n

返回签名支付信息的对应代码:

def get_pay_sign_info(self, prepay_id): ts = int(time.time()) nonce = self.generate_nonce() content = '{}\n{}\n{}\n{}\n'.format(self.mch_appid, ts, nonce, prepay_id) digest = SHA256.new(content.encode('utf-8')) sign_v = base64.b64encode(self.signer.sign(digest)).decode('utf-8') return { 'appid': self.mch_appid, 'partnerid': self.mchid, 'timestamp': str(ts), 'noncestr': nonce, 'prepay_id': prepay_id, 'package': 'Sign=WXPay', 'sign': sign_v, } 业务后端查询订单详情

文档地址:pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_2.shtml
代码如下:

def query_order(self, out_trade_no): ''' 查询指定订单信息 ''' url = f'api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}?mchid={self.mchid}' headers = self.make_headers_v3(url) rsp = requests.get(url, headers=headers) pay_logger.info('out_trade_no:{}, rsp:{}|{}'.format(out_trade_no, rsp.status_code, rsp.text)) rdct = rsp.json() return rdct 业务后端调用APP下单API

文档地址:pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
代码如下:

def create_order_info(self, data, callback_url): ''' 创建微信预支付订单, 注意包含两次签名过程: 首次签名用于请求微信后端获取prepay_id 二次签名信息返回客户端用于调起SDK支付 ''' url = 'api.mch.weixin.qq.com/v3/pay/transactions/app' ndt = datetime.now() out_trade_no = self.generate_partner_trade_no(ndt) data = { 'mchid': self.mchid, 'out_trade_no': out_trade_no, 'appid': self.mch_appid, 'description': data['subject'], 'notify_url': callback_url, 'amount': { 'currency': 'CNY', 'total': int(data['price']), }, 'time_expire': (ndt + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S+08:00') } jdata = json.dumps(data, separators=[',', ':']) headers = {'Content-Type': 'application/json'} # 第一次签名, 直接请求微信后端 headers = self.make_headers_v3(url, headers=headers, body=jdata, method='POST') rsp = requests.post(url, headers=headers, data=jdata) pay_logger.info('rsp:{}|{}'.format(rsp.status_code, rsp.text)) rdct = rsp.json() # 第二次签名, 返回给客户端调用 sign_info = self.get_pay_sign_info(rdct['prepay_id']) return sign_info 源码地址

试水代码开源,把相关代码分享在了github:github.com/liuzhi67/wechat-pay-python

转载请注明出处,原文地址:www.cnblogs.com/AcAc-t/p/wechat_pay_by_python.html

签名:拥抱开源,拥抱自由