# 参数签名规则

在金币发放和虚拟支付功能中,为了应对安全风险,有些接口采用了签名校验机制。因此,在请求相关接口时,需要根据接口约定,对指定的业务参数进行签名,并由小游戏平台对签名进行校验。 签名算法相同,参与签名的字段详见各接口说明。

金币发放、虚拟支付功能中使用的签名密钥均为开放平台的App Secret。

# 签名规则

# 签名过程描述

  1. 将参与签名的请求参数及其取值写成key=value的形式,然后按参数名升序排列,并用&连接,得到拼接字符串。形式如:k1=v1&k2=v2
  2. 使用签名密钥,对拼接字符串使用HMAC-SHA256算法进行计算,得到签名

说明:

  • 计算签名使用从开放平台获得的签名密钥(即App Secret),参数签名建议放在服务端进行,避免将签名密钥放在游戏包内,以免密钥泄露。
  • 签名/验签时请务必排除取值为空的字段

# 签名流程举例(Java版)

  1. 在开放平台获取到签名密钥
String signKey = "B7Y0c6E5bCKMEQOsvCExziNhq16ObGqh";
  1. 收集请求参数
{
       "open_id": "open001",
       "app_id": "kwaiApp001",
       "zone_id": "server1_role1",
       "os": "android",
       "currency_type": "USD",
       "buy_quantity": 99,
       "user_ip": "127.0.0.1",
       "third_party_trade_no": "third001",
       "extension": "{}"
}
  1. 按照key=value的格式,并按照参数名ASCII字典序升序排列,得到拼接字符串
String joinedString = "app_id=kwaiApp001&buy_quantity=99&currency_type=USD&extension={}&open_id=open001&os=android&third_party_trade_no=third001&user_ip=127.0.0.1&zone_id=server1_role1";
  1. 使用签名密钥,对拼接字符串使用算法HMAC-SHA256进行计算,得到签名
String sig = sha256Hmac(joinedString, signKey)
           = d8e898cc271725ea93b38801418759ffb0a36b2a16a5078dc08e8fc13890758a

# 相关实现

HMAC-SHA256算法

public static String sha256Hmac(String message, String secret) {
    String hash = "";
    try {
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
        sha256Hmac.init(secretKey);
        byte[] bytes = sha256Hmac.doFinal(message.getBytes());
        hash = byteArrayToHexString(bytes);
    } 
    catch (Exception e) {
        logger.error("sha256Hmac exception :{},:{}", message, secret, e);
    }
    return hash;
}

byte字符串转hex字符串

private static String byteArrayToHexString(byte[] b) {
    StringBuilder hs = new StringBuilder();
    String stmp;
    for (int n = 0; b != null && n < b.length; n++) {
        stmp = Integer.toHexString(b[n] & 0XFF);
        if (stmp.length() == 1) {
            hs.append('0');
        }
        hs.append(stmp);
    }
    return hs.toString().toLowerCase();
}