package jwtx import ( "base-go-v2/internal/config" "time" "github.com/golang-jwt/jwt/v5" ) // CustomClaims 自定义 payload,可扩展其他信息 type CustomClaims struct { UserID int64 `json:"user_id"` // 改为 int jwt.RegisteredClaims } // TokenResult 用于返回验证结果 type TokenResult struct { Claims *CustomClaims IsValid bool IsExpired bool } // CreateAccessToken 创建 Access Token,只返回 token 和 error func CreateAccessToken(userID int64) (string, error) { return createToken(userID, config.App.JWT.AccessExpiry) } // CreateRefreshToken 创建 Refresh Token,只返回 token 和 error func CreateRefreshToken(userID int64) (string, error) { return createToken(userID, config.App.JWT.RefreshExpiry) } // 内部方法,根据过期时间生成 token func createToken(userID int64, expiry time.Duration) (string, error) { claims := &CustomClaims{ UserID: userID, RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(time.Now()), }, } switch { case expiry > 0: expireAt := time.Now().Add(expiry) claims.ExpiresAt = jwt.NewNumericDate(expireAt) case expiry == -1: claims.ExpiresAt = nil // 永不过期 default: expireAt := time.Now().Add(time.Hour) claims.ExpiresAt = jwt.NewNumericDate(expireAt) } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) signed, err := token.SignedString([]byte(config.App.JWT.Secret)) if err != nil { return "", err } return signed, nil } // VerifyToken 验证 token 并返回结构化结果 func VerifyToken(tokenString string) TokenResult { result := TokenResult{ IsValid: false, IsExpired: false, } // 🧩 1. token 为空 if tokenString == "" { return result } // 🧩 2. 解析 token token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(config.App.JWT.Secret), nil }) // 🧩 3. token 为 nil(解析异常) if token == nil { return result } // 🧩 4. 提取 claims 并验证 claims, ok := token.Claims.(*CustomClaims) if !ok { return result } // 🧩 5. 解析失败或签名无效 if err != nil || !token.Valid { return result } // ✅ 6. 填充结果 result.Claims = claims result.IsValid = true // 🧩 7. 检查是否过期 if claims.ExpiresAt != nil && time.Now().After(claims.ExpiresAt.Time) { result.IsExpired = true } return result }