package middlewares import ( "net/http" "strings" "time" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "go.uber.org/zap" ) var ( jwtSecret []byte jwtIssuer string expireHours int ) // JWTClaims JWT声明结构 type JWTClaims struct { UserID int `json:"user_id"` Username string `json:"username"` jwt.RegisteredClaims } // InitJWT 初始化JWT配置 func InitJWT(secret string, expire int, issuer string) { jwtSecret = []byte(secret) expireHours = expire jwtIssuer = issuer } // GenerateToken 生成JWT token func GenerateToken(userID int, username string) (string, error) { claims := JWTClaims{ UserID: userID, Username: username, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHours) * time.Hour)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), Issuer: jwtIssuer, }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(jwtSecret) } // ParseToken 解析JWT token func ParseToken(tokenString string) (*JWTClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid { return claims, nil } return nil, jwt.ErrTokenInvalidClaims } // JWTAuth JWT认证中间件 func JWTAuth() gin.HandlerFunc { return func(c *gin.Context) { // 从Header获取token authHeader := c.GetHeader("Authorization") if authHeader == "" { Logger.Warn("JWT认证失败:缺少Authorization头部", zap.String("path", c.Request.URL.Path), zap.String("client_ip", c.ClientIP()), ) c.JSON(http.StatusOK, gin.H{ "code": 401, "message": "缺少认证token", }) c.Abort() return } // Bearer token格式检查 if !strings.HasPrefix(authHeader, "Bearer ") { Logger.Warn("JWT认证失败:token格式错误", zap.String("auth_header", authHeader), zap.String("path", c.Request.URL.Path), zap.String("client_ip", c.ClientIP()), ) c.JSON(http.StatusOK, gin.H{ "code": 401, "message": "token格式错误", }) c.Abort() return } tokenString := strings.TrimPrefix(authHeader, "Bearer ") // 解析token claims, err := ParseToken(tokenString) if err != nil { Logger.Warn("JWT认证失败:token解析错误", zap.Error(err), zap.String("path", c.Request.URL.Path), zap.String("client_ip", c.ClientIP()), ) c.JSON(http.StatusOK, gin.H{ "code": 401, "message": "token无效或已过期", }) c.Abort() return } // 将用户信息存储到上下文 c.Set("user_id", claims.UserID) c.Set("username", claims.Username) Logger.Debug("JWT认证成功", zap.Int("user_id", claims.UserID), zap.String("username", claims.Username), zap.String("path", c.Request.URL.Path), ) c.Next() } } // GetCurrentUser 从上下文获取当前用户信息 func GetCurrentUser(c *gin.Context) (int, string, bool) { userID, userExists := c.Get("user_id") username, nameExists := c.Get("username") if !userExists || !nameExists { return 0, "", false } return userID.(int), username.(string), true }