This repository has been archived on 2024-11-28. You can view files and clone it, but cannot push or open issues or pull requests.
Files
schisandra-cloud-album/middleware/verify_signature.go
2024-11-03 17:13:08 +08:00

96 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package middleware
import (
"bytes"
"crypto/md5"
"encoding/hex"
"io"
"net/http"
"strconv"
"time"
ginI18n "github.com/gin-contrib/i18n"
"github.com/gin-gonic/gin"
"schisandra-cloud-album/common/constant"
"schisandra-cloud-album/common/redis"
"schisandra-cloud-album/common/result"
"schisandra-cloud-album/global"
)
func VerifySignature() gin.HandlerFunc {
return func(c *gin.Context) {
// 仅处理 POST 请求
if c.Request.Method != http.MethodPost {
c.Next()
return
}
// 从请求头获取签名和时间戳
signature := c.GetHeader("X-Sign")
timestamp := c.GetHeader("X-Timestamp")
nonce := c.GetHeader("X-Nonce")
secretKey := global.CONFIG.Encrypt.Key
// 检查时间戳是否过期这里设置为5分钟过期
if timestamp == "" || time.Since(parseTimestamp(timestamp)) > 5*time.Minute {
result.FailWithMessage(ginI18n.MustGetMessage(c, "RequestVerifyError"), c)
c.Abort()
return
}
// 检查 nonce 是否已经被使用
if data := redis.Get(constant.SystemApiNonceRedisKey + nonce).Val(); data != "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "RequestVerifyError"), c)
c.Abort()
return
}
// 记录 nonce 到 Redis 中,并设置过期时间为 5 分钟
if err := redis.Set(constant.SystemApiNonceRedisKey+nonce, true, 5*time.Minute).Err(); err != nil {
global.LOG.Error(err.Error())
c.Abort()
return
}
// 获取请求方法和请求体
var payload string
if c.Request.Method == http.MethodPost {
body, err := io.ReadAll(c.Request.Body)
if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "RequestReadError"), c)
c.Abort()
return
}
payload = string(body)
// 重新设置请求体,以便后续处理中可以再次读取
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
}
// 创建待签名字符串
baseString := c.Request.Method + ":" + payload + ":" + timestamp + ":" + nonce + ":" + secretKey
// 生成 MD5 签名
h := md5.New()
h.Write([]byte(baseString))
expectedSignature := hex.EncodeToString(h.Sum(nil))
// 验证签名
if signature != expectedSignature {
result.FailWithMessage(ginI18n.MustGetMessage(c, "RequestVerifyError"), c)
c.Abort()
return
}
// 继续处理请求
c.Next()
}
}
// 辅助函数:解析时间戳
func parseTimestamp(ts string) time.Time {
t, err := strconv.ParseInt(ts, 10, 64)
if err != nil {
return time.Time{} // 解析错误返回零时间
}
return time.Unix(t/1000, 0) // 假设时间戳是毫秒
}