Чёрный список токенов
Чёрный список используется для принудительной аннулиации токенов до истечения их срока действия. Применяется при выходе пользователя из системы, смене пароля, изменении прав доступа и других сценариях.
Принцип работы
Revoke(token) → извлечение jti + exp → запись в BlacklistStore
Validate(token) → проверка подписи → проверка чёрного списка → возврат результатаВстроенное хранилище в памяти
По умолчанию используется хранилище в памяти, готовое к работе без настройки:
cfg := jwt.DefaultConfig()
cfg.SecretKey = "hmac-key-that-has-at-least-32-bytes!"
// Чёрный список уже автоматически включён, используется DefaultBlacklistConfig()Параметры конфигурации
cfg.Blacklist.CleanupInterval = 5 * time.Minute // Интервал очистки
cfg.Blacklist.MaxSize = 100000 // Максимальное количество записей
cfg.Blacklist.EnableAutoCleanup = true // Автоматическая очистка| Поле | По умолчанию | Описание |
|---|---|---|
CleanupInterval | 5m | Интервал очистки просроченных записей |
MaxSize | 100000 | Максимальное количество записей |
EnableAutoCleanup | true | Автоматическая очистка (принудительно true) |
Автоматическая очистка
EnableAutoCleanup встроенного хранилища всегда принудительно установлено в true для предотвращения неограниченного роста памяти.
Отзыв токена
// Отзыв
err := processor.Revoke(accessToken)
if err != nil {
panic(err)
}
// Проверка
revoked, err := processor.IsRevoked(accessToken)
fmt.Println("Revoked:", revoked) // true
// Проверка отозванного токена завершится ошибкой
_, _, err = processor.Validate(accessToken)
// err → jwt.ErrTokenRevokedПользовательский бэкенд хранилища
Реализуйте интерфейс BlacklistStore для подключения к внешнему хранилищу (Redis, база данных и т.д.):
type BlacklistStore interface {
Add(tokenID string, expiresAt time.Time) error
Contains(tokenID string) (bool, error)
Close() error
}Пример с Redis
type RedisStore struct {
client *redis.Client
}
func (s *RedisStore) Add(tokenID string, expiresAt time.Time) error {
ttl := time.Until(expiresAt)
if ttl <= 0 {
return nil // Просроченный токен не нужно хранить
}
return s.client.Set(ctx, "blacklist:"+tokenID, "1", ttl).Err()
}
func (s *RedisStore) Contains(tokenID string) (bool, error) {
n, err := s.client.Exists(ctx, "blacklist:"+tokenID).Result()
return n > 0, err
}
func (s *RedisStore) Close() error {
return s.client.Close()
}Использование пользовательского хранилища:
cfg.Blacklist.Store = &RedisStore{client: rdb}Оптимизация TTL
Используйте time.Until(expiresAt) в качестве Redis TTL. Токен автоматически удалится из чёрного списка после истечения срока действия без дополнительной очистки.
Рекомендации для производственной среды
Важные замечания
- Встроенное хранилище в памяти не разделяется между процессами; при развёртывании нескольких экземпляров используйте внешнее хранилище
- При достижении лимита
MaxSizeновые отзываемые токены вытесняют самые старые записи - Реализация пользовательского хранилища должна обрабатывать сетевые тайм-ауты и повторные попытки
Дальнейшие шаги
- Справочник API → BlacklistStore — определение интерфейса
- Справочник API → BlacklistConfig — поля конфигурации
- Справочник API → Revoke — метод отзыва
- Продвинутые примеры — пример чёрного списка с Redis