A 模式签名规则(md5-timestamp-rand)¶
概述¶
A 模式是基于 MD5 哈希算法的鉴权方式,通过时间戳和随机字符串确保签名的唯一性和时效性。
签名格式¶
A 模式的签名格式如下:
鉴权字段说明¶
| 字段 | 说明 |
|---|---|
| timestamp | 秒级 Unix 时间戳(整数)。 |
| Path | 请求路径(不包含参数,例如https://test.com/demo.js?id=1234中的/demo.js)。 |
| rand | 0 - 100 位随机字符串,由大小写字母与数字组成。 |
| secret | 客户端持有的鉴权密钥,必须在服务端 密钥 列表中。 |
| md5hash | 明文的 MD5 值(32 位小写),md5hash = md5(Path-timestamp-rand-secret)。 |
获取鉴权参数¶
- Path:/demo.js。
- timestamp:服务端生成鉴权 URL 的时间为2024年7月15日 15:27:17(UTC+8),转换为十进制(Unix 时间戳)格式的数值为1721028437。
- rand:生成随机数为 Kv4cPTAAP5YTi。
- 密钥:DvYmqE81E1F9R791H6lmht。
- md5hash:MD5(Path-timestamp-rand-密钥)= MD5(/demo.js-1721028437-Kv4cPTAAP5YTi-DvYmqE81E1F9R791H6lmht)= 0fbdca749d7ab784750685347e42075c。
客户端请求示例¶
GET /demo.js HTTP/1.1
Host: test.com
x-security-auth: 0fbdca749d7ab784750685347e42075c-1721028437-Kv4cPTAAP5YTi
节点鉴权¶
当节点服务器接收到客户端通过加密 URL 发出的请求时,解析出 signature 中的 timestamp 参数,加上配置的有效时长“1秒”,与当前时间比较:
1. 若当前时间超过“timestamp + 有效时长”时间,则为过期请求,直接返回418。若当前时间未超过“timestamp + 有效时长”时间,则请求未过期,继续第 2 步。
2. 节点服务器通过获取的鉴权参数计算 md5hash 值,与请求 signature 中携带的 md5hash 值做比较:两值相同,鉴权通过,响应请求;两值不同,鉴权失败,返回 418。
JavaScript 实现示例¶
/**
* 生成 A 模式 signature
* @param {string} uri 请求路径,例如 "/demo.js"
* @param {string} secret 鉴权密钥
* @returns {Promise<string>} 生成的签名字符串
*/
async function generateSignatureTypeA(uri, secret) {
// 1. 获取当前秒级时间戳
const timestamp = Math.floor(Date.now() / 1000);
// 2. 生成 12 位随机字符串
const rand = randomString(12);
// 3. 按照规则拼接明文
const plaintext = `${uri}-${timestamp}-${rand}-${secret}`;
// 4. 计算明文的 MD5 值(32 位小写)
const md5hex = await md5Hex(plaintext);
// 5. 组合生成最终的 signature
return `${md5hex}-${timestamp}-${rand}`;
}
/**
* 生成指定长度的随机字符串
* @param {number} length 字符串长度,默认 12
* @returns {string} 随机字符串
*/
function randomString(length = 12) {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const bytes = new Uint8Array(length);
crypto.getRandomValues(bytes);
let out = "";
for (let i = 0; i < length; i++) {
out += chars[bytes[i] % chars.length];
}
return out;
}
/**
* MD5 哈希函数实现
* @param {string} input 输入字符串
* @returns {Promise<string>} MD5 哈希值(32 位小写)
* @note 请替换为项目中实际使用的 MD5 实现,例如 crypto-js、blueimp-md5 等库
*/
async function md5Hex(input) {
return md5(input).toLowerCase();
}