Files
lijiaoqiao/supply-api/internal/middleware/token_revocation_service.go

75 lines
2.4 KiB
Go
Raw Normal View History

package middleware
import (
"context"
"time"
"lijiaoqiao/supply-api/internal/cache"
)
// TokenRevocationService Token吊销服务P0-03修复
// 实现主动失效机制,确保吊销传播延迟 <= 5s
type TokenRevocationService struct {
redisCache TokenCacheBackend
dbBackend TokenRevocationBackend
}
// TokenRevocationBackend Token吊销数据库后端接口
type TokenRevocationBackend interface {
// RevokeToken 在数据库中吊销token
RevokeToken(ctx context.Context, tokenID string, reason string) error
// GetTokenStatus 获取token状态
GetTokenStatus(ctx context.Context, tokenID string) (string, error)
}
// NewTokenRevocationService 创建Token吊销服务
func NewTokenRevocationService(redisCache TokenCacheBackend, dbBackend TokenRevocationBackend) *TokenRevocationService {
return &TokenRevocationService{
redisCache: redisCache,
dbBackend: dbBackend,
}
}
// RevokeAndPublish 吊销token并发布吊销事件主动失效机制核心
// 步骤:
// 1. 更新数据库状态
// 2. 发布吊销事件到Redis Pub/Sub
// 3. 返回成功(异步传播到所有缓存节点)
func (s *TokenRevocationService) RevokeAndPublish(ctx context.Context, tokenID string, reason string) error {
// 1. 更新数据库状态(同步)
if err := s.dbBackend.RevokeToken(ctx, tokenID, reason); err != nil {
return err
}
// 2. 发布吊销事件到Redis Pub/Sub异步触发主动失效
revokeEvent := &cache.TokenRevokedCacheEvent{
TokenID: tokenID,
RevokedAt: time.Now(),
Reason: reason,
}
// 发布操作需要成功,否则缓存可能不会及时失效
if err := s.redisCache.PublishTokenRevoked(ctx, revokeEvent); err != nil {
// 发布失败时,至少要确保本地缓存失效
s.redisCache.InvalidateToken(ctx, tokenID)
return err
}
return nil
}
// StartRevocationSubscriber 启动吊销事件订阅者
// 在应用启动时调用启动后台goroutine监听吊销事件
func (s *TokenRevocationService) StartRevocationSubscriber(ctx context.Context) error {
return s.redisCache.SubscribeTokenRevoked(ctx, func(event *cache.TokenRevokedCacheEvent) {
// 收到吊销事件,立即失效本地缓存
s.redisCache.InvalidateToken(ctx, event.TokenID)
})
}
// RevokeLocalOnly 仅在本地缓存失效(不发布事件,用于测试或特殊场景)
func (s *TokenRevocationService) RevokeLocalOnly(ctx context.Context, tokenID string) error {
s.redisCache.InvalidateToken(ctx, tokenID)
return nil
}