package jwt import ( "context" "errors" "github.com/gogf/gf/v2/frame/g" "server/utility/ecode" "strings" "time" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" ) var ( secretKey = []byte("1a40c1d5b7a1b0f0fasdfaf835e0b24ca292a6") issuer = "novel" ) type ( TokenIn struct { UserId int64 // 用户 ID Role string // 权限标识 } TokenOut struct { UserId int64 // 用户 ID Role string // 权限标识 JTI string // JWT 唯一标识 } jwtClaims struct { UserId int64 `json:"user_id"` // 用户 ID Role string `json:"Role"` // 权限标识 JTI string `json:"jti"` // 唯一标识 jwt.RegisteredClaims } ) func GenerateToken(in *TokenIn) (string, error) { claims := jwtClaims{ UserId: in.UserId, Role: in.Role, JTI: uuid.NewString(), RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), Issuer: issuer, }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(secretKey) } func ParseToken(tokenString string) (*TokenOut, error) { if strings.HasPrefix(tokenString, "Bearer ") { tokenString = strings.TrimPrefix(tokenString, "Bearer ") } token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) { return secretKey, nil }) if err != nil { if errors.Is(err, jwt.ErrTokenExpired) { return nil, ecode.Expire.Sub("token_expired") } return nil, ecode.Fail.Sub("token_parse_failed") } claims, ok := token.Claims.(*jwtClaims) if !ok || !token.Valid { return nil, ecode.InvalidOperation.Sub("invalid_token") } blacklist, err := isBlacklist(claims.JTI) if err != nil { return nil, ecode.Fail.Sub("token_parse_failed") } if blacklist { return nil, ecode.InvalidOperation.Sub("token_expired") } return &TokenOut{ UserId: claims.UserId, Role: claims.Role, JTI: claims.JTI, }, nil } func isBlacklist(uuid string) (bool, error) { exitst, err := g.Redis().Exists(context.Background(), "blacklist:"+uuid) if err != nil { return false, err } return exitst > 0, nil }