package services import ( "errors" "time" "github.com/golang-jwt/jwt/v4" "gorm.io/gorm" ) type TokenService struct { db *gorm.DB keyManager *KeyManager } type TokenInfo struct { Active bool `json:"active"` Scope string `json:"scope,omitempty"` ClientID string `json:"client_id,omitempty"` Username string `json:"username,omitempty"` TokenType string `json:"token_type,omitempty"` Exp int64 `json:"exp,omitempty"` Iat int64 `json:"iat,omitempty"` Nbf int64 `json:"nbf,omitempty"` Sub string `json:"sub,omitempty"` Aud string `json:"aud,omitempty"` Iss string `json:"iss,omitempty"` Jti string `json:"jti,omitempty"` } type RevokedToken struct { gorm.Model Token string `gorm:"uniqueIndex;not null"` ExpiresAt time.Time `gorm:"not null"` } func NewTokenService(db *gorm.DB, keyManager *KeyManager) *TokenService { return &TokenService{ db: db, keyManager: keyManager, } } func (s *TokenService) RevokeToken(token, tokenTypeHint string) error { // 验证令牌 claims, err := s.parseToken(token) if err != nil { return err } // 保存到撤销列表 revokedToken := &RevokedToken{ Token: token, ExpiresAt: time.Unix(claims["exp"].(int64), 0), } return s.db.Create(revokedToken).Error } func (s *TokenService) IntrospectToken(token, tokenTypeHint string) (*TokenInfo, error) { // 检查令牌是否被撤销 var revokedToken RevokedToken if err := s.db.Where("token = ?", token).First(&revokedToken).Error; err == nil { return &TokenInfo{Active: false}, nil } // 解析令牌 claims, err := s.parseToken(token) if err != nil { return &TokenInfo{Active: false}, nil } // 检查令牌是否过期 exp := time.Unix(claims["exp"].(int64), 0) if time.Now().After(exp) { return &TokenInfo{Active: false}, nil } // 构建令牌信息 info := &TokenInfo{ Active: true, Scope: claims["scope"].(string), ClientID: claims["iss"].(string), TokenType: "Bearer", Exp: claims["exp"].(int64), Iat: claims["iat"].(int64), Sub: claims["sub"].(string), } return info, nil } func (s *TokenService) parseToken(token string) (jwt.MapClaims, error) { parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, errors.New("unexpected signing method") } return s.keyManager.GetPrivateKey().Public(), nil }) if err != nil { return nil, err } if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok && parsedToken.Valid { return claims, nil } return nil, errors.New("invalid token") } func (s *TokenService) AutoMigrate() error { return s.db.AutoMigrate(&RevokedToken{}) }