104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
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())
|
||
}
|