Files
spage/utils/token.go
2025-06-18 18:38:53 +08:00

81 lines
2.2 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 utils
import (
"github.com/LiteyukiStudio/spage/config"
"github.com/LiteyukiStudio/spage/spage/models"
"time"
"github.com/golang-jwt/jwt/v5"
"gorm.io/gorm"
)
type TokenType struct{}
var Token = TokenType{}
type Claims struct {
jwt.RegisteredClaims
UserID uint `json:"user_id"` // 用户ID用于身份验证 Verify user identity using the User ID
TokenID uint `json:"token_id"` // 令牌ID用于服务端会话维持 Keep the token ID for server-side session maintenance
Stateful bool `json:"stateful"` // 是否为有状态Token Whether it is a stateful Token
}
// CreateToken 生成用户会话令牌默认24小时有效
// stateful=false的无状态Token不会做持久化在实例重启后失效
// Create a user session token (default 24 hours valid)
// stateful=false tokens are not persistent, and they will expire after the instance restarts
func (TokenType) CreateToken(userID uint, duration time.Duration, stateful bool, persistentHandler func(uint) (*models.Token, error)) (string, error) {
var tokenModel *models.Token
var err error
if stateful {
tokenModel, err = persistentHandler(userID)
if err != nil {
return "", err
}
} else {
tokenModel = &models.Token{
Model: gorm.Model{
ID: 0,
},
}
}
claims := Claims{
UserID: userID,
TokenID: tokenModel.ID,
Stateful: stateful,
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(duration)),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(config.JwtSecret))
}
// ParseToken 解析JWT令牌
// Parse JWT token
func (TokenType) ParseToken(tokenString string, revokeChecker func(uint) bool) (*Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (any, error) {
return []byte(config.JwtSecret), nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, jwt.ErrSignatureInvalid
}
// 有状态token被吊销也视为过期
// Revoked stateful tokens are considered expired
if claims.Stateful {
if revokeChecker(claims.UserID) {
return nil, jwt.ErrTokenExpired
}
}
return claims, nil
}