Вопрос с собеседования · Spring

Метод помечен @Async, и внутри него SecurityContextHolder.getContext().getAuthentication() возвращает null. Почему?

MiddleSpring Security
Ещё спрашивают так:
  • Как передать пользователя в @Async-метод?
Коротко

SecurityContext хранится в ThreadLocal потока запроса и в асинхронный поток сам не переезжает. Решение — DelegatingSecurityContextAsyncTaskExecutor (или TaskDecorator), который копирует контекст.

  • То же для MDC с trace id — TaskDecorator
  • Режим MODE_INHERITABLETHREADLOCAL не подходит для пулов — потоки переиспользуются
  • Виртуальные потоки не меняют проблему

А ещё Context Propagation (Micrometer) переносит контекст автоматически

Подробно

Стратегия хранения по умолчанию — MODE_THREADLOCAL, поэтому любой переход в другой поток теряет контекст: это касается @Async, задач в собственном пуле и реактивных цепочек. Варианты решения: включить MODE_INHERITABLETHREADLOCAL, что работает для потоков, созданных напрямую, но бесполезно для пула, где потоки существовали заранее; либо, что правильнее, обернуть исполнитель в DelegatingSecurityContextExecutor или DelegatingSecurityContextAsyncTaskExecutor, который явно переносит контекст в задачу. В WebFlux механизм другой — контекст живёт в Reactor Context, а не в ThreadLocal. И совсем простой вариант: передать нужные данные о пользователе параметрами метода, не полагаясь на неявное состояние.

Что хотят услышать

  • Причина: ThreadLocal.
  • Правильное решение с executor'ом.
  • Почему не inheritable для пулов.

Частые ошибки

  • Рассчитывать, что MODE_INHERITABLETHREADLOCAL решит проблему для пула потоков.
  • Полагаться на SecurityContextHolder внутри реактивных цепочек.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗@Async несовместим со Spring Security, и аутентификация в таком методе всегда равна null
  • ✓Контекст лежит в ThreadLocal и не переходит в поток @Async без делегирующего executor
  • ✗Аутентификация истекает при выходе из метода контроллера
  • ✗Нужно пометить метод дополнительно аннотацией @PreAuthorize

Что спросят дальше

  • Почему наследуемый ThreadLocal не помогает с пулом?
  • Как устроено распространение контекста в WebFlux?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования