外观
鉴权与签名
除回调接收端外,所有 Open API 请求都需要以下 Header:
| Header | 说明 |
|---|---|
Dujiao-Next-Api-Key | 用户生成的 API Key |
Dujiao-Next-Timestamp | Unix 秒级时间戳 |
Dujiao-Next-Signature | HMAC-SHA256 签名,小写十六进制 |
Content-Type | application/json |
签名串
严格按照以下四行拼接:
text
{METHOD}\n{PATH}\n{TIMESTAMP}\n{BODY_MD5}| 部分 | 规则 |
|---|---|
METHOD | 大写 HTTP 方法,例如 GET、POST |
PATH | 仅请求路径,不含域名和查询参数 |
TIMESTAMP | 与请求头时间戳完全一致 |
BODY_MD5 | 实际请求体字节的 MD5,小写十六进制 |
无请求体时,MD5 固定为:
text
d41d8cd98f00b204e9800998ecf8427eAPI Secret 如何参与签名
API_SECRET 不是直接拼接到签名串中,而是先转换为 UTF-8 字节,并作为 HMAC-SHA256 的密钥:
text
secret_bytes = UTF8(API_SECRET)
message_bytes = UTF8(sign_string)
signature_bytes = HMAC-SHA256(key=secret_bytes, message=message_bytes)
signature = HEX_LOWER(signature_bytes)完整关系:
text
API_SECRET
→ UTF-8 bytes
→ 作为 HMAC-SHA256 key
METHOD + PATH + TIMESTAMP + BODY_MD5
→ sign_string
→ UTF-8 bytes
→ 作为 HMAC-SHA256 message
HMAC 结果
→ 小写十六进制
→ Dujiao-Next-Signature不要先对 API_SECRET 做 MD5 或 SHA256。MD5 只用于请求体 body,API_SECRET 原始 UTF-8 字节直接作为 HMAC key。
Python
python
import hashlib
import hmac
import time
method = "GET"
path = "/api/v1/upstream/products"
timestamp = str(int(time.time()))
body = b""
body_md5 = hashlib.md5(body).hexdigest()
sign_string = f"{method}\n{path}\n{timestamp}\n{body_md5}"
secret_bytes = API_SECRET.encode("utf-8")
message_bytes = sign_string.encode("utf-8")
signature = hmac.new(
secret_bytes,
message_bytes,
hashlib.sha256,
).hexdigest()Go
go
bodyMD5 := md5.Sum(body)
signString := strings.Join([]string{
method,
path,
timestamp,
hex.EncodeToString(bodyMD5[:]),
}, "\n")
secretBytes := []byte(apiSecret)
messageBytes := []byte(signString)
mac := hmac.New(sha256.New, secretBytes)
mac.Write(messageBytes)
signature := hex.EncodeToString(mac.Sum(nil))容易出错的地方
/products?page=2签名时的PATH仍是/api/v1/upstream/products,不包含查询字符串。- POST JSON 必须先序列化成最终发送的字节,再计算 MD5;签名后不要重新格式化 JSON。
- 时间戳只允许约
±60秒偏差,服务器必须保持时间同步。 - 签名和 MD5 都使用小写十六进制。
- 不要把 Secret 放进 URL、浏览器脚本或日志。
签名测试向量
text
method: GET
path: /api/v1/upstream/products
timestamp: 1700000000
body: <empty>
secret: test_secret期望签名:
text
eebf4100af7232ab580df9acddc32784aff5257e14c96d776668c7855dcfb3a1