# 虚拟支付签名
# 支付请求签名(pay_sig)算法说明
pay_sig 参数的签名算法,使用“mp-支付基础配置”中的 AppKey 对支付的请求进行签名 后台签名 pay_sig 代表请求经过开发者服务端的支付模块发起。签名算法伪代码为:
pay_sig = to_hex(hmac_sha256(app_key, uri + '&' + post_body))
可以参考以下 python 示例中的 calc_pay_sig 实现,其中: 如为后台 api
- uri 为不带参数的 API 路径,如: /wxa/game/getbalance /wxa/game/pay /wxa/game/cancelpay /wxa/game/present
- app_key 为当前支付环境(env 参数)对应的 AppKey,从“mp-支付基础配置”处获取
- post_body 为该 API(和 uri 对应)要求的原始 http 请求 post 的数据,参考具体接口的请求参数说明
#!/usr/bin/python
# -*- coding: utf-8 -*-
""" pay_sig签名算法计算示例 """
import hmac
import hashlib
import json
import time
def calc_pay_sig(uri, post_body, appkey):
""" pay_sig签名算法
Args:
uri - 当前请求的支付API的uri部分,不带query_string
例如:/wxa/game/getbalance、/wxa/game/pay
post_body - http POST的数据包体
appkey - 对应环境的AppKey
Returns:
支付请求签名pay_sig
"""
need_sign_msg = uri + '&' + post_body
pay_sig = hmac.new(key = appkey.encode('utf-8'), msg = need_sign_msg.encode('utf-8'),
digestmod=hashlib.sha256).hexdigest()
return pay_sig
# uri,切记不可带参数,即去掉"?"及后面的部分
# 其他值如: /wxa/game/pay、/wxa/game/cancelpay、/wxa/game/present
uri = '/wxa/game/getbalance'
# 此处appkey为假设值,实际使用应根据支付环境(env参数)替换为对应的AppKey
appkey = "12345"
# 注意:JSON数据序列化结果,不同语言/版本结果可能不同
# 所以示例为了保证稳定性,直接用其中一个序列化的版本
# 实际使用时只需要保证,参与签名的post_body和真正发起http请求的一致即可
"""
# ts需要设置为当前unix timestap(秒级)
# 实际使用时可参考: int(time.time())
# 此处写死方便稳定复现算法
ts = 1668136271
# 不同接口要求的Post Body参数不一样,此处以getBalance接口为例(和uri对应)
post_body = json.dumps({
"offer_id": "12345678",
"openid": "oUrsfxxxxxxxxxx",
"ts": ts,
"zone_id": "1",
"env": 0
})
"""
post_body = '{"offer_id": "12345678", "openid": "oUrsfxxxxxxxxxx", "ts": 1668136271, "zone_id": "1", "env": 0}'
# pay_sig签名计算(支付请求签名算法)
pay_sig = calc_pay_sig(uri, post_body, appkey)
print("pay_sig:", pay_sig)
# 若实际请求返回pay_sig签名不对,根据以下步骤排查:
# 1. 确认算法:uri、post_body、appkey写死以上参数,确保你的签名算法和示例calc_pay_sig结果完全一致
# 2. 确认参数:
# - uri不可带参数(即"?"及后续部分全部舍去)
# - post_body必须和真正发起HTTP请求的post body完全一致
# - appkey必须是与请求中对应的环境匹配(env参数决定)
assert pay_sig == "11bac6388871d29c055c7d16fbe42e8d646855b666faf89b15c815218b1b23bd"
# 用户登录态签名(signature)签名算法
可以参考用户登录态签名,也可以参考随后 python 示例中 calc_signature 实现。
#!/usr/bin/python
# -*- coding: utf-8 -*-
""" pay_sig签名算法计算示例 """
import hmac
import hashlib
import json
import time
def calc_signature(post_body, session_key):
""" 用户登录态signature签名算法
Args:
post_body - http POST的数据包体
session_key - 当前用户有效的session_key,参考auth.code2Session接口
Returns:
用户登录态签名signature
"""
need_sign_msg = post_body
signature = hmac.new(key = session_key.encode('utf-8'), msg = need_sign_msg.encode('utf-8'),
digestmod=hashlib.sha256).hexdigest()
return signature
# 此处appkey为假设值,实际使用应根据支付环境(env参数)替换为对应的AppKey
appkey = "12345"
# 注意:JSON数据序列化结果,不同语言/版本结果可能不同
# 所以示例为了保证稳定性,直接用其中一个序列化的版本
# 实际使用时只需要保证,参与签名的post_body和真正发起http请求的一致即可
"""
# ts需要设置为当前unix timestap(秒级)
# 实际使用时可参考: int(time.time())
# 此处写死方便稳定复现算法
ts = 1668136271
# 不同接口要求的Post Body参数不一样,此处以getBalance接口为例(和uri对应)
post_body = json.dumps({
"offer_id": "12345678",
"openid": "oUrsfxxxxxxxxxx",
"ts": ts,
"zone_id": "1",
"env": 0
})
"""
post_body = '{"offer_id": "12345678", "openid": "oUrsfxxxxxxxxxx", "ts": 1668136271, "zone_id": "1", "env": 0}'
# signature签名计算(用户登录态签名算法)
# session_key需要为当前用户有效session_key(参考auth.code2Session接口获取)
# 此处写死方便复现算法
session_key = "9hAb/NEYUlkaMBEsmFgzig=="
signature = calc_signature(post_body, session_key)
print("signature:", signature)
# 若实际请求返回signature签名不对,参考随后的“90010-signature签名错误问题排查思路”进行排查
assert signature == "42fe1d3341fb1c8bd6f5014ba735ab04eacc80a2deb3ab4669eab4700b5b6729"