# 虚拟支付签名

# 支付请求签名(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"