签名算法
签名用于验证请求合法性,防止参数被篡改。当前 API 使用 HMAC-SHA256,密钥为软件的 App Secret。
签名步骤
- 收集所有请求参数(不含
sign字段本身),包括 Body 参数或 Query 参数 - 按参数名字典升序排列,拼接为
k1=v1&k2=v2&...kn=vn - 拼接签名原文:
HTTP方法 + Host + 接口路径 + 参数字符串 - 使用
App Secret作为 HMAC 密钥,对签名原文计算 HMAC-SHA256,输出小写十六进制字符串
签名公式
// 伪代码
params = 所有参数(不含sign),按key升序排列
paramStr = params.map(k => k+"="+v).join("&")
raw = METHOD + host + path + paramStr
sign = HMAC_SHA256(app_secret, raw).toLowerCase()
Host必须与实际请求 URL 的 host 一致,包含端口。例如本地开发环境通常是localhost:3000。
TypeScript 示例
import { createHmac, randomBytes } from "node:crypto";
function randomNonce() {
return randomBytes(8).toString("hex");
}
function calcSign(
method: string,
host: string,
path: string,
params: Record<string, string | number>,
appSecret: string,
) {
const paramStr = Object.keys(params)
.filter((key) => key !== "sign")
.sort()
.map((key) => `${key}=${params[key]}`)
.join("&");
const raw = `${method.toUpperCase()}${host}${path}${paramStr}`;
return createHmac("sha256", appSecret).update(raw).digest("hex");
}
const params = {
app_key: "your_app_key",
card: "XXXX-XXXX-XXXX-XXXX",
device_id: "device-001",
nonce: randomNonce(),
timestamp: Math.floor(Date.now() / 1000),
};
const sign = calcSign("POST", "ttqsoft.com", "/api/v1/card/login", params, "your_app_secret");
C# 示例
using System.Security.Cryptography;
using System.Text;
string CalcSign(string method, string host, string path,
Dictionary<string, string> prms, string secret) {
var sorted = prms
.Where(kv => kv.Key != "sign")
.OrderBy(kv => kv.Key)
.Select(kv => $"{kv.Key}={kv.Value}");
string paramStr = string.Join("&", sorted);
string raw = method.ToUpper() + host + path + paramStr;
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(raw));
return Convert.ToHexString(hash).ToLower();
}
Python 示例
import hmac, hashlib, time, secrets
def calc_sign(method, host, path, params, secret):
items = sorted(
[(k, v) for k, v in params.items() if k != "sign"],
key=lambda x: x[0]
)
param_str = "&".join(f"{k}={v}" for k, v in items)
raw = method.upper() + host + path + param_str
return hmac.new(secret.encode(), raw.encode(), hashlib.sha256).hexdigest()
# 示例
params = {
"app_key": "your_app_key",
"card": "XXXX-XXXX-XXXX",
"device_id": "device_001",
"nonce": secrets.token_hex(8),
"timestamp": int(time.time()),
}
params["sign"] = calc_sign("POST", "your.domain.com",
"/api/v1/card/login", params, "your_app_secret")
注意事项
- GET 请求的参数在 Query String 中;POST 请求的参数在 JSON Body 中
Host为请求的域名(含端口,如有),例如verify.example.comApp Secret在开发者控制台获取,请勿泄露给最终用户