为了保证 API 请求数据的完整性、防止请求参数被篡改,接口采用:
作为请求签名算法。
客户端调用 API
时,需要按照约定规则对请求参数进行排序、拼接,然后使用应用密钥(Secret)计算签名。
服务端收到请求后,使用相同算法重新计算签名,并与客户端提交的签名进行比对。
请求参数
|
↓
参数排序
|
↓
key=value 拼接
|
↓
HMAC-SHA1(secret)
|
↓
HEX编码
|
↓
Base64编码
|
↓
生成 signature
参数 类型 说明
appId String 应用唯一标识
secret String 应用密钥,用于签名计算
version String API版本号,默认 1.0
Secret 只能保存在服务端,不允许暴露给客户端。
参数 类型 必填 说明
appId String 是 应用ID
nonce String 是 随机字符串
timestamp Long 是 Unix时间戳(秒)
data String 是 业务数据
version String 是 接口版本
signature String 是 签名结果
示例:
{
"appId": "test_app_001",
"nonce": "abc123",
"timestamp": 1754870400,
"version": "1.0",
"data": "{\"userId\":10001}",
"signature": "xxxxxxxx"
}
所有参与签名的参数按照参数名称 ASCII 升序排序。
排序示例:
appId
data
nonce
timestamp
version
按照:
key=value
格式生成字符串。
多个参数使用:
&
连接。
示例:
appId=test_app&data=hello&nonce=abc×tamp=1754870400&version=1.0
计算:
HMAC-SHA1(secret, plainText)
最终签名:
signature = Base64(HMAC-SHA1结果)
function makeSign(params, secret){
const plainText = Object.keys(params)
.sort()
.map(key => `${key}=${params[key]}`)
.join("&");
const sha1 = HmacSHA1(
plainText,
secret
);
return Base64(sha1);
}
如果 data 是对象:
JSON.stringify(data)
转换为字符串后参与签名。
单位:
秒
生成:
Math.floor(Date.now() / 1000)
收到请求
|
↓
检查 timestamp 是否有效
|
↓
移除 signature 字段
|
↓
重新计算签名
|
↓
比较 signature
|
↓
一致: 请求合法
不一致: 拒绝请求
默认有效时间:
90秒
规则:
当前时间戳 - 请求timestamp <= 90
超过有效时间:
拒绝请求
nonce 用于防止请求重放攻击。
建议:
项目 推荐
长度 >=16字符
类型 随机字符串
使用次数 单次请求唯一
参与签名的 data 必须保持完全一致。
例如:
{"a":1,"b":2}
和:
{"b":2,"a":1}
虽然 JSON 含义相同,但是字符串不同,会导致签名不一致。
客户端和服务端必须统一序列化规则。
参与签名:
appId
data
nonce
timestamp
version
排序:
ASCII升序
拼接:
key=value&key=value
算法:
HMAC-SHA1
编码:
HEX → Base64
有效时间:
90秒
项目 建议
Secret保存 仅服务端保存
HTTPS 必须开启
timestamp 限制请求时间
nonce 防止重放
Secret长度 建议32位以上
SHA算法 新系统推荐升级 SHA256