签名生成

更新时间:2020-08-20

准备

在进行下面的步骤之前,需要先获取 shop_app_keyshop_app_secret 两个字符串。

  • 确保从开发者平台得到的 app_idapp_secret (server版本)的正确性及完整性
  • 使用 动态链接库(0.0.4) 进行解密获得 shop_app_keyshop_app_secret

c 头文件

#ifndef DECRYPT_LIBRARY_H
#define DECRYPT_LIBRARY_H
#include <stdint.h>
char *decrypt(char *appID, char *cipherText);
void release(char *plainText);
#endif //DECRYPT_LIBRARY_H

构造签名串

请按照当前文档约定的规则构造签名串。

LinkV 会使用同样的方式构造签名串。如果接入方构造签名串的方式错误,将导致签名验证不通过

签名串是一个 32位 长度的字符串。

计算签名值

第一步:拼接字符串(原串)

设所有发送或者接收到的数据为 集合M,将 nonce 参数 随机字符串 加入,将 集合M 内非空参数值的参数按照 参数名ASCII码 从小到大 排序(字典序),使用 URL键值对 的格式(key1=value1&key2=value2…),拼接成字符串 stringA

特别注意以下重要规则:

  • 参数名 ASCII 从小到大排序(字典序);
  • 如果参数的值为空不参与签名
  • 参数名区分大小写
  • nonce随机字符串,前八位和后八位为随机字符串,中间为秒级时间戳
    • 例子: 661a3893156378771361c1a022 其中前后八位为随机字符串,中间为秒级时间戳:1563787713
    • 接口会校验时间戳,5分钟内位有效校验时间,如果超过5分钟则校验失败

假设传送的参数如下:

"app_id": "LM6000101140927991745433"

"params1": "t1"

"a123": ""

对参数按照 key=value 的格式,并按照参数名 ASCII 字典序排序如下:

StringA = "app_id=LM6000101140927991745433&nonce_str=24dcadd615637909402f4877b0&param1=t1"

第二步:生成签名串

签名校验算法为 md5 ,在 stringA 最后拼接上 key=shop_app_secret 得到 stringSignTemp 字符串,并对 stringSignTemp 进行 MD5 运算,转为小写,生成 sign签名

假设原串如下:

StringA = “app_id=LM6000101140927991745433&nonce_str=24dcadd615637909402f4877b0&param1=t1”

拼接 API密钥 (shop_app_secret)

StringA2 = "app_id=LM6000101140927991745433&nonce_str=24dcadd615637909402f4877b0&param1=t1&key=live_app_secret"

sign = Tolower(md5(StringA2)) = "864070ea8d99310992fbbb1d8579f674"

示例代码

Go

...

func genRandomString() string {
    nLen := 16
    var container string
    var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
    b := bytes.NewBufferString(str)
    length := b.Len()
    bigInt := big.NewInt(int64(length))
    for i := 0; i < nLen; i++ {
        randomInt, _ := rand.Int(rand.Reader, bigInt)
        container += string(str[randomInt.Int64()])
        if i == 7 {
            container += strconv.FormatInt(time.Now().Unix(), 10)
        }
    }
    return container
}

func genSign(params url.Values, md5Secret string) string {
    data := encode(params) + "&key=" + md5Secret
    md5Data := md5.Sum([]byte(data))
    return strings.ToLower(hex.EncodeToString(md5Data[:]))
}

func encode(v url.Values) string {
    if v == nil {
        return ""
    }
    var buf strings.Builder
    keys := make([]string, 0, len(v))
    for k := range v {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    for _, k := range keys {
        vs := v[k]
        if buf.Len() > 0 {
            buf.WriteByte('&')
        }
        buf.WriteString(k)
        buf.WriteByte('=')
        buf.WriteString(vs[0])
    }
    return buf.String()
}

...

func ...(...) {
    ... 
    nonce := genRandomString()
    params.Add("nonce", nonce)
    params.Add("app_id", ShopAppKey)

    params.Add("user_id", thirdUID)
    params.Add("aid", aID)

    if len(userName) > 0 {
        params.Add("name", userName)
    }

    params.Add("sign", genSign(params, ShopAppSecret))
    ...
}