添加jwt验证方法

This commit is contained in:
2025-08-10 02:10:41 +08:00
parent 0abdb5e5e5
commit 525ad7b7ff

106
utill/jwtUt.go Normal file
View File

@@ -0,0 +1,106 @@
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. 存储到Redisjwt:{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 {
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()
}
}