Лекция 11. Spring Security
Что такое Spring Security
Spring Security — Java/Java EE фреймворк, предоставляющий механизмы построения систем аутентификации и авторизации, а также другие возможности обеспечения безопасности для корпоративных приложений на Spring Framework.
Архитектура: цепочка фильтров
Spring Security использует паттерн «Цепочка обязанностей» (Chain of Responsibility). При выполнении HTTP-запроса происходит поэтапная обработка фильтрами, которые производят валидацию запроса.
Основные фильтры Spring Security
WebAsyncManagerIntegrationFilter
Интегрирует SecurityContext с WebAsyncManager, который ответственен за асинхронные запросы.
SecurityContextPersistenceFilter
- Ищет
SecurityContextв сессии - Заполняет
SecurityContextHolder, если находит - По умолчанию используется
ThreadLocalSecurityContextHolderStrategy, хранящийSecurityContextвThreadLocal-переменной
HeaderWriterFilter
Просто добавляет заголовки в response.
LogoutFilter
Проверяет совпадает ли URL с паттерном (/logout POST по умолчанию) и запускает процедуру логаута:
- Удаляется CSRF-токен
- Завершается сессия
- Чистится
SecurityContextHolder
BasicAuthenticationFilter
- Проверяет, есть ли заголовок
Authorization: Basic ... - Если находит — извлекает логин/пароль и передаёт их в
AuthenticationManager
RequestCacheAwareFilter
Восстанавливает оригинальный запрос пользователя после логина:
- Пользователь заходит на защищённый URL
- Его перекидывает на страницу логина
- После успешной авторизации — возвращает на исходную страницу
Внутри проверяет, есть ли сохранённый запрос, и подменяет им текущий. Запрос сохраняется в сессии.
AnonymousAuthenticationFilter
Если к моменту выполнения этого фильтра SecurityContextHolder пуст (т.е. аутентификации не произошло), фильтр заполняет его анонимной аутентификацией — AnonymousAuthenticationToken с ролью ROLE_ANONYMOUS.
Это гарантирует, что в SecurityContextHolder всегда будет объект — можно не бояться NullPointerException и более гибко настраивать доступ для неавторизованных пользователей.
SessionManagementFilter
На этом этапе производятся действия, связанные с сессией:
- Смена идентификатора сессии
- Ограничение количества одновременных сессий
- Сохранение
SecurityContextвsecurityContextRepository
В обычном случае:
HttpSessionSecurityContextRepositoryсохраняетSecurityContextв сессию- Вызывается
sessionAuthenticationStrategy.onAuthentication - По умолчанию включена защита от session fixation attack — после аутентификации меняется ID сессии
- Если был передан CSRF-токен — генерируется новый
ExceptionTranslationFilter
К этому моменту SecurityContext должен содержать анонимную или нормальную аутентификацию. Этот фильтр прокидывает запрос/ответ по filter chain и обрабатывает возможные ошибки авторизации.
FilterSecurityInterceptor
На последнем этапе происходит авторизация на основе URL запроса.
- Наследуется от
AbstractSecurityInterceptor - Решает, имеет ли текущий пользователь доступ к URL
- Существует другая реализация —
MethodSecurityInterceptor— для допуска к методам (при использовании@Secured/@PreAuthorize) - Внутри вызывается
AccessDecisionManager - Несколько стратегий принятия решения, по умолчанию: AffirmativeBased
AuthenticationManager
AuthenticationManager — интерфейс, который принимает Authentication и возвращает Authentication. Это центральная точка процесса аутентификации.
Типичная реализация Authentication — UsernamePasswordAuthenticationToken.
ProviderManager
ProviderManager — стандартная реализация AuthenticationManager. Содержит список AuthenticationProvider.
AuthenticationProvider
Когда мы передаём объект Authentication в ProviderManager, он:
- Перебирает существующие
AuthenticationProvider-ы - Проверяет, поддерживает ли
AuthenticationProviderэту имплементациюAuthentication - Внутри
AuthenticationProvider.authenticateмы приводим переданныйAuthenticationк нужной реализации - Извлекаем credentials
- Если аутентификация не удалась — выбрасываем исключение
- ProviderManager ловит исключение и пробует следующий провайдер
- Если ни один провайдер не вернул успешную аутентификацию — ProviderManager пробрасывает последнее пойманное исключение
После успешной аутентификации BasicAuthenticationFilter сохраняет полученный Authentication:
SecurityContextHolder.getContext().setAuthentication(authResult);
Если выбрасывается AuthenticationException — контекст сбрасывается, вызывается AuthenticationEntryPoint.