package utill import ( "fmt" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "time" "toutoukan/config" "toutoukan/init/redisInit" "toutoukan/model/usermodel" ) // 生成JWT并存储到Redis func GenerateJWTAndStore(openid string) (string, error) { // 1. 生成JWT expirationTime := time.Now().Add(2 * time.Hour) claims := &usermodel.JWTClaims{ OpenID: openid, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(expirationTime), IssuedAt: jwt.NewNumericDate(time.Now()), Issuer: "toutoukan", }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(config.Conf.Jwtsecret)) if err != nil { return "", err } // 2. 存储到Redis(键:jwt:{token},值:openid,过期时间与JWT一致) redisKey := fmt.Sprintf("jwt:%s", tokenString) err = redisInit.RedisClient.Set( redisInit.Ctx, redisKey, openid, 2*time.Hour, ).Err() return tokenString, err } // 验证JWT并检查Redis func ValidateJWTWithRedis(tokenString string) (*usermodel.JWTClaims, error) { // 1. 先验证JWT签名和过期时间 token, err := jwt.ParseWithClaims( tokenString, &usermodel.JWTClaims{}, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, jwt.ErrSignatureInvalid } return []byte(config.Conf.Jwtsecret), nil }, ) if err != nil { return nil, err } // 2. 验证Redis中是否存在(防止已登出的令牌) redisKey := fmt.Sprintf("jwt:%s", tokenString) exists, err := redisInit.RedisClient.Exists(redisInit.Ctx, redisKey).Result() if err != nil { return nil, fmt.Errorf("redis查询失败: %w", err) } if exists == 0 { return nil, fmt.Errorf("令牌已失效") } // 3. 验证声明有效性 if claims, ok := token.Claims.(*usermodel.JWTClaims); ok && token.Valid { return claims, nil } return nil, jwt.ErrSignatureInvalid } // 辅助函数:从请求头提取令牌 func ExtractTokenFromHeader(c *gin.Context) string { authHeader := c.GetHeader("Authorization") var tokenString string fmt.Sscanf(authHeader, "Bearer %s", &tokenString) return tokenString } // JWT+Redis验证中间件 func JWTAuthMiddleware() gin.HandlerFunc { fmt.Println("验证请求") return func(c *gin.Context) { tokenString := ExtractTokenFromHeader(c) if tokenString == "" { c.JSON(401, gin.H{"error": "请先登录", "code": "10033"}) c.Abort() return } claims, err := ValidateJWTWithRedis(tokenString) if err != nil { c.JSON(401, gin.H{"error": "令牌无效或已过期", "code": "10034"}) c.Abort() return } c.Set("openid", claims.OpenID) c.Next() } }