topfans/backend/pkg/jwt/jwt.go
2026-04-07 22:29:48 +08:00

104 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package jwt
import (
"errors"
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
const (
// TokenExpiration Token过期时间7天
TokenExpiration = 7 * 24 * time.Hour
)
var (
// jwtSecret JWT签名密钥应该从环境变量或配置文件读取
jwtSecret = []byte("your-secret-key-change-in-production")
)
// SetSecret 设置JWT签名密钥应该在服务启动时调用
func SetSecret(secret string) {
jwtSecret = []byte(secret)
}
// Claims JWT Claims结构
type Claims struct {
UserID int64 `json:"user_id"`
StarID int64 `json:"star_id"`
UpdatedAt int64 `json:"updated_at"`
jwt.RegisteredClaims
}
// GenerateToken 生成JWT Token
func GenerateToken(userID, starID int64, updatedAt int64) (string, error) {
now := time.Now()
expiresAt := now.Add(TokenExpiration)
claims := Claims{
UserID: userID,
StarID: starID,
UpdatedAt: updatedAt,
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(now),
ExpiresAt: jwt.NewNumericDate(expiresAt),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtSecret)
if err != nil {
return "", fmt.Errorf("failed to sign token: %w", err)
}
return tokenString, nil
}
// ParseToken 解析JWT Token不验证过期时间用于刷新Token场景
func ParseToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
// 验证签名算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return jwtSecret, nil
})
if err != nil {
return nil, fmt.Errorf("failed to parse token: %w", err)
}
claims, ok := token.Claims.(*Claims)
if !ok || !token.Valid {
return nil, errors.New("invalid token claims")
}
return claims, nil
}
// ValidateToken 验证Token检查签名和过期时间
func ValidateToken(tokenString string) (*Claims, error) {
claims, err := ParseToken(tokenString)
if err != nil {
return nil, err
}
// 验证过期时间
if claims.ExpiresAt != nil && claims.ExpiresAt.Time.Before(time.Now()) {
return nil, errors.New("token expired")
}
return claims, nil
}
// GetExpiresAt 获取Token过期时间戳毫秒
func GetExpiresAt() int64 {
return time.Now().Add(TokenExpiration).UnixMilli()
}
// GetExpiresIn 获取Token过期时间
func GetExpiresIn() int64 {
return int64(TokenExpiration.Seconds())
}