package jwtx import ( "allapp/config" "context" "errors" "sync" "time" "github.com/golang-jwt/jwt/v5" ) type CustomClaims struct { UserID int64 `json:"user_id"` jwt.RegisteredClaims } // jwtManager 单例管理 type jwtManager struct { secret string tokenExpiry time.Duration } var ( manager *jwtManager once sync.Once ) // InitJwt 初始化 JWT 单例 func InitJwt() { once.Do(func() { cfg := config.GetConf().JWT manager = &jwtManager{ secret: cfg.Secret, tokenExpiry: cfg.AccessExpiry, } }) } // CreateToken 生成 JWT func CreateToken(ctx context.Context, userID int64) (string, error) { if manager == nil { return "", errors.New("jwt manager not initialized") } return manager.createToken(userID) } // VerifyToken 校验 token 并返回 claims func VerifyToken(ctx context.Context, tokenString string) (*CustomClaims, error) { if tokenString == "" || manager == nil { return nil, errors.New("token empty or manager not initialized") } token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(manager.secret), nil }) if err != nil || !token.Valid { return nil, errors.New("invalid token") } claims, ok := token.Claims.(*CustomClaims) if !ok { return nil, errors.New("invalid claims") } return claims, nil } // createToken 私有方法 func (j *jwtManager) createToken(userID int64) (string, error) { now := time.Now() claims := &CustomClaims{ UserID: userID, RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(now), }, } if j.tokenExpiry > 0 { claims.ExpiresAt = jwt.NewNumericDate(now.Add(j.tokenExpiry)) } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(j.secret)) }