# 签名机制

# 1. 签名方法

签名时,您需要在项目详情页面查看目前项目的 accessKey 和 accessSecret。其中 accessKey 用于标识访问者身份;accessSecret 用于对称加密时的密钥,应严格保密,不能在空中传播;若泄露,可在项目详情里刷新。

  • 签名方法
sign = sign_method(accessSecret, "accessKey{accessKey}timestamp{timestamp}random{randomStr}signMethod{signMethod}").HexToString()
  • 算法逻辑
  1. randomStr 和时间戳防重放,timestamp 取当前时间戳,单位秒,10 分钟误差,randomStr 取 uuid,10 分钟内只能使用一次;sign_method 为签名算法;

  2. 待加密字符串需按指定顺序拼接;

  3. 将字符串和 secret 进行哈希,得到签名字符串,并转为十六进制小写字符串;

# 2. 签名示例

一个用户的连接信息为:

accessKey: "GmXM0L69da381d51"
accessSecret: "04d711bd2390ae4f605caff758df90e5"
randomStr: "ae1786"
signMethod: "hmacsha1"
timestamp: "1631585734"

通过签名方法得到的新的签名:

sign = hmacsha1("04d711bd2390ae4f605caff758df90e5", "accessKeyGmXM0L69da381d51timestamp1631585734randomae1786signMethodhmacsha1")

计算得到的签名字符串为:

068baf6ed7a9f2c6df9f5d8f870b5add7460cf8b

请求头参数为:

access_key: GmXM0L69da381d51
sign: 068baf6ed7a9f2c6df9f5d8f870b5add7460cf8b
sign_method: hmacsha1
timestamp: 1631585734
random_str: ae1786

# 3. 代码示例

# 3.1 java

package example;

import java.security.Timestamp;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public class SignUtils {
    private static String accessKey = "GmXM0L69da381d51";
    private static String accessSecret = "04d711bd2390ae4f605caff758df90e5";
    private static String timestamp = "1631585734";
    private static String randomStr = "ae1786";
    private static String signMethod = "HmacSHA1";

    public static void main(String[] args) throws Exception {
        String sign = genHmacsha1Sign(accessKey, accessSecret);
        System.out.println("sign: " + sign);
    }

    private static String genHmacsha1Sign(String accessKey, String secret) throws Exception {
        String plainText = genSignString(accessKey, secret, timestamp, randomStr);
        byte[] rawBytes = hmacsha1Sign(plainText);
        return bytes2hex(rawBytes);
    }

    private static String genSignString(String accessKey, String secret, String timestamp, String randomStr) {
        StringBuilder plainText = new StringBuilder();
        plainText.append("accessKey").append(accessKey);
        plainText.append("timestamp").append(timestamp);
        plainText.append("random").append(randomStr);
        plainText.append("signMethod").append("hmacsha1");
        return plainText.toString();
    }

    private static byte[] hmacsha1Sign(String signString) throws Exception {  
        Mac mac = Mac.getInstance(signMethod);
        SecretKeySpec keySpec = new SecretKeySpec(accessSecret.getBytes("utf8"), signMethod);
        mac.init(keySpec);
        return mac.doFinal(signString.getBytes("utf8"));
    }

    private static String bytes2hex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte aByte : bytes) {
            result.append(String.format("%02x", aByte));
        }
        return result.toString();
    }
}

# 3.2 golang

package main

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"fmt"
	"hash"
)

const (
	accessKey    = "GmXM0L69da381d51"
	accessSecret = "04d711bd2390ae4f605caff758df90e5"
)

func main() {
	signMethod := "hmacsha1"
	timestamp := "1631585734"
	randomStr := "ae1786"
	sign, _ := authSign(accessKey, timestamp, randomStr, accessSecret, signMethod)
	fmt.Println("signature: ", sign)
}

func authSign(accessKey, timestamp, randomStr, accessSecret, signMethod string) (string, error) {
	src := ""
	src = fmt.Sprintf("accessKey%stimestamp%srandom%ssignMethod%s", accessKey, timestamp, randomStr, signMethod)
	var h hash.Hash
	switch signMethod {
	case "hmacsha1":
		h = hmac.New(sha1.New, []byte(accessSecret))
	case "hmacmd5":
		h = hmac.New(md5.New, []byte(accessSecret))
	default:
		return "", errors.New("invalid sign method")
	}

	_, err := h.Write([]byte(src))
	if err != nil {
		return "", err
	}
	return hex.EncodeToString(h.Sum(nil)), nil
}

# 3.3 python

import hmac,hashlib

access_key    = "GmXM0L69da381d51"
access_secret = "04d711bd2390ae4f605caff758df90e5"
timestamp = "1631585734"
sign_method = "hmacsha1"
random_str = "ae1786"

def gen_sign_str(access_key, timestamp, sign_method, random_str):
    plaintext = 'accessKey{}timestamp{}random{}signMethod{}'.format(access_key, timestamp, random_str, sign_method)
    return plaintext

def sign(access_key, access_secret, timestamp, sign_method, random_str):
    plaintext = gen_sign_str(access_key, timestamp, sign_method, random_str)
    return hmac.new(bytes(access_secret, encoding="utf-8"), bytes(plaintext, encoding="utf-8"),hashlib.sha1).hexdigest()

if __name__ == '__main__':
    signature = sign(access_key, access_secret, timestamp, sign_method, random_str)
    print("sign: ", signature)
更新时间: 2023/2/15 下午3:19:08