优化签名排序逻辑
This commit is contained in:
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user