DeployHelper/internal/middleware/jwt.go

92 lines
2.2 KiB
Go
Raw Normal View History

2025-08-01 16:38:08 +08:00
package middleware
import (
"ego/internal/serializer"
"ego/internal/util"
"ego/pkg/logger"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// AuthRequired 验证 JWT 的中间件
func AuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
// 获取Authorization头
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
sendUnauthorized(c, "缺少认证头")
return
}
// 检查Bearer前缀
if !strings.HasPrefix(authHeader, "Bearer ") {
sendUnauthorized(c, "无效的认证格式请使用Bearer Token")
return
}
// 提取token
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
if tokenString == "" {
sendUnauthorized(c, "Token不能为空")
return
}
// 验证token
claims, err := util.ValidateToken(tokenString)
if err != nil {
logger.Error(c, "Token验证失败", zap.Error(err))
sendUnauthorized(c, "Token验证失败: "+err.Error())
return
}
// 检查Redis中的token状态
redisKey := util.TokenGroup + claims.Username
val, err := util.Get(c, redisKey)
if err != nil {
logger.Error(c, "Redis验证失败",
zap.Error(err),
zap.String("redisKey", redisKey))
sendUnauthorized(c, "登录状态验证失败")
return
}
if val == "" {
logger.Warn(c, "Token已过期或已注销",
zap.String("username", claims.Username))
sendUnauthorized(c, "登录状态已过期,请重新登录")
return
}
// 验证Redis中的token是否与当前token一致
if val != tokenString {
logger.Warn(c, "Token不匹配可能存在重复登录",
zap.String("username", claims.Username))
sendUnauthorized(c, "登录状态异常,请重新登录")
return
}
// 将用户信息存储到context中
c.Set("userID", claims.ID)
c.Set("username", claims.Username)
c.Set("id", claims.ID) // 保持向后兼容
logger.Debug(c, "JWT认证成功",
zap.String("userID", claims.ID),
zap.String("username", claims.Username))
c.Next()
}
}
// sendUnauthorized 发送401未授权响应
func sendUnauthorized(c *gin.Context, message string) {
c.AbortWithStatusJSON(http.StatusUnauthorized, serializer.Response{
Code: http.StatusUnauthorized,
Msg: message,
Data: nil,
})
}