优化签名排序逻辑

This commit is contained in:
yml2213
2026-07-20 16:34:23 +08:00
parent e4d0a71963
commit ee78b80cd3
3 changed files with 108 additions and 54 deletions
+32 -23
View File
@@ -6,6 +6,7 @@ import (
"crypto/sha256"
"encoding/hex"
"io"
"sort"
"strconv"
"strings"
"sync"
@@ -37,7 +38,6 @@ func newNonceStore() *nonceStore {
func (s *nonceStore) seen(nonce string, now, ttl int64) bool {
s.mu.Lock()
defer s.mu.Unlock()
// 清理过期
for k, exp := range s.data {
if exp < now {
delete(s.data, k)
@@ -52,11 +52,15 @@ func (s *nonceStore) seen(nonce string, now, ttl int64) bool {
// OpenAuth 校验 X-Api-Key + 时间戳 + nonce + HMAC-SHA256 签名
//
// 待签名字符串(UTF-8\n 换行):
// 待签名参数(value 原样,不做 URL encode):
//
// {apiKey}\n{timestamp}\n{nonce}\n{METHOD}\n{path}\n{body}
// api_key, body, method, nonce, path, timestamp
//
// path 为 URL.Path(不含 query),METHOD 大写;GET 时 body 为空字符串。
// 按 key 字典序排序后拼接:
//
// k1=v1&k2=v2&...
//
// method 大写;path 为 URL.Path(不含 query);GET 时 body 为空串。
// sign = hex(hmac_sha256(apiSecret, stringToSign)),小写十六进制。
func OpenAuth(cfg OpenAuthConfig) gin.HandlerFunc {
if cfg.SkewSeconds <= 0 {
@@ -105,7 +109,6 @@ func OpenAuth(cfg OpenAuthConfig) gin.HandlerFunc {
return
}
// 防重放:同一 nonce 在时间窗口内只能用一次
if store.seen(apiKey+":"+nonce, now, cfg.SkewSeconds) {
response.Unauthorized(c, "重复的 X-Nonce(请勿重放请求)")
c.Abort()
@@ -124,15 +127,7 @@ func OpenAuth(cfg OpenAuthConfig) gin.HandlerFunc {
path := c.Request.URL.Path
body := string(bodyBytes)
stringToSign := strings.Join([]string{
apiKey,
timestamp,
nonce,
method,
path,
body,
}, "\n")
stringToSign := BuildSignString(apiKey, timestamp, nonce, method, path, body)
expected := hmacSHA256Hex(cfg.APISecret, stringToSign)
if !hmac.Equal([]byte(strings.ToLower(sign)), []byte(expected)) {
response.Unauthorized(c, "签名校验失败")
@@ -144,6 +139,28 @@ func OpenAuth(cfg OpenAuthConfig) gin.HandlerFunc {
}
}
// BuildSignString 生成待签名字符串:参数字典序 + & 拼接
func BuildSignString(apiKey, timestamp, nonce, method, path, body string) string {
params := map[string]string{
"api_key": apiKey,
"body": body,
"method": strings.ToUpper(method),
"nonce": nonce,
"path": path,
"timestamp": timestamp,
}
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
parts := make([]string, 0, len(keys))
for _, k := range keys {
parts = append(parts, k+"="+params[k])
}
return strings.Join(parts, "&")
}
func hmacSHA256Hex(secret, content string) string {
mac := hmac.New(sha256.New, []byte(secret))
_, _ = mac.Write([]byte(content))
@@ -159,13 +176,5 @@ func abs64(v int64) int64 {
// BuildOpenSign 供测试或内部生成签名(与 OpenAuth 规则一致)
func BuildOpenSign(apiKey, apiSecret, timestamp, nonce, method, path, body string) string {
stringToSign := strings.Join([]string{
apiKey,
timestamp,
nonce,
strings.ToUpper(method),
path,
body,
}, "\n")
return hmacSHA256Hex(apiSecret, stringToSign)
return hmacSHA256Hex(apiSecret, BuildSignString(apiKey, timestamp, nonce, method, path, body))
}