# 虚拟支付签名
# 支付请求签名(pay_sig)算法说明
pay_sig参数的签名算法,使用“开放能力-小游戏内购-基础配置”中的支付Key对支付的请求进行签名 后台签名pay_sig代表请求经过开发者服务端的支付模块发起。签名算法伪代码为:
pay_sig = to_hex(hmac_sha256(app_key, uri + '&' + post_body))
可以参考以下python示例中的calc_pay_sig实现,其中: 如为后台api
- uri为不带参数的API路径,如: /order/v1/detail
- 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
例如:/order/v1/detail
post_body - http POST的数据包体
appkey - 对应环境的支付Key
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,切记不可带参数,即去掉"?"及后面的部分
# 其他值如: /order/v1/detail
uri = '/order/v1/detail'
# 此处appkey为假设值,实际使用应根据支付环境(env参数)替换为对应的支付Key
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"