92 lines
2.2 KiB
Go
92 lines
2.2 KiB
Go
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,
|
||
})
|
||
}
|