Как обрабатывается авторизация в Spring Security
Что проверяют
Знаете ли вы, что происходит с запросом внутри цепочки фильтров, а не только как выглядит конфиг. И актуален ли опыт: WebSecurityConfigurerAdapter удалён в Spring Security 6, и пример с ним сразу выдаёт старые знания. Следом спрашивают, чем 401 отличается от 403 и кто их формирует.
Как отвечать
Путь запроса:
- цепочка фильтров:
DelegatingFilterProxyпередаёт запрос вFilterChainProxy, тот выбирает подходящий бинSecurityFilterChain; - аутентификация: фильтры вроде
BearerTokenAuthenticationFilterкладутAuthenticationс наборомGrantedAuthorityвSecurityContextHolder, по умолчанию он хранится вThreadLocal; - авторизация запроса:
AuthorizationFilterв конце цепочки спрашиваетAuthorizationManager, есть ли доступ. Он заменил старую связкуAccessDecisionManagerи голосующих; - отказ:
AccessDeniedExceptionловитExceptionTranslationFilter. Анонимному отвечаетAuthenticationEntryPoint(401 или редирект на логин), аутентифицированномуAccessDeniedHandlerс 403.
Правила задаются в бине SecurityFilterChain через authorizeHttpRequests и requestMatchers("/admin/**").hasRole("ADMIN"), в конце anyRequest().authenticated(). Старые authorizeRequests и antMatchers в новом коде не используют.
Второй уровень, методы: @EnableMethodSecurity, затем @PreAuthorize("hasRole('ADMIN')"), @PostAuthorize, @PreFilter и @PostFilter. В @PreAuthorize можно проверить и владельца объекта, например #id == authentication.name. Для JWT ресурс-сервер по умолчанию превращает scope токена в права вида SCOPE_read, роли из своего claim маппятся конвертером.
Где спотыкаются
Путают hasRole и hasAuthority. hasRole("ADMIN") ищет право ROLE_ADMIN, и если в базе роль записана без префикса, доступа не будет.
Ставят anyRequest() раньше конкретных правил. Правила проверяются по порядку до первого совпадения, а современные версии такой конфиг вообще не запускают.
Вешают @PreAuthorize на приватный метод или вызывают защищённый метод из того же класса. Проверку делает прокси, вызов через this его обходит, и аннотация молча не работает.