Spring Security кажется магией, пока не увидишь, что это просто цепочка фильтров. На собесе спрашивают, как проходит запрос через Security, чем аутентификация отличается от авторизации, как сделать JWT и OAuth2, что такое CSRF и CORS.
Аутентификация и авторизация
- Аутентификация: кто ты (логин и пароль, токен, сертификат). Ошибка даёт 401 Unauthorized.
- Авторизация: что тебе можно (роли, права). Ошибка даёт 403 Forbidden.
Цепочка фильтров
Spring Security встраивается в сервлет-контейнер одним фильтром DelegatingFilterProxy, который передаёт запрос в FilterChainProxy, а тот в подходящую SecurityFilterChain. Внутри цепочки фильтры по порядку: CORS, CSRF, аутентификация (форма, Basic, Bearer-токен), обработка исключений (ExceptionTranslationFilter), авторизация (AuthorizationFilter).
Результат аутентификации кладётся в SecurityContextHolder (по умолчанию ThreadLocal), откуда его берут контроллеры, @PreAuthorize и аудит.
Конфигурация в Security 6
WebSecurityConfigurerAdapter удалён, конфигурация это бин SecurityFilterChain и лямбда-DSL:
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain api(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // stateless API с токенами
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**", "/actuator/health").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))
.build();
}
}
Правила проверяются сверху вниз до первого совпадения: широкое правило выше узкого перекроет его. Заканчивать стоит anyRequest().authenticated() или denyAll().
hasRole("ADMIN") проверяет authority ROLE_ADMIN, а hasAuthority("ADMIN") ровно ADMIN. Путаница префикса частая причина 403.
Пароли
Пароли хранят только хешем с солью медленным алгоритмом: BCryptPasswordEncoder, Argon2, PBKDF2. PasswordEncoderFactories.createDelegatingPasswordEncoder() пишет префикс {bcrypt} и позволяет мигрировать алгоритмы. MD5, SHA-256 без соли и обратимое шифрование не годятся.
JWT и OAuth2
Для API без сессий клиент присылает Authorization: Bearer <jwt>. Resource Server (spring-boot-starter-oauth2-resource-server) проверяет подпись по ключам издателя (issuer-uri или jwk-set-uri), срок, издателя и превращает claims в authorities.
- Access-токен короткий (минуты), refresh-токен длинный, хранится безопасно и ротируется.
- JWT нельзя отозвать до истечения без чёрного списка: поэтому короткий срок.
- В JWT не кладут секреты: payload только закодирован base64url, не зашифрован.
- Алгоритм проверки задаётся сервером, а не берётся из заголовка токена (атака
alg: none).
Логин через внешнего провайдера (Keycloak, Google) это oauth2Login и Authorization Code с PKCE.
Методная безопасность
@EnableMethodSecurity включает @PreAuthorize("hasRole('ADMIN')"), @PreAuthorize("#userId == authentication.name"). Работает через прокси: те же ограничения, что у @Transactional (this-вызовы, private).
CSRF и CORS
- CSRF: чужой сайт отправляет запрос от имени пользователя, браузер сам прикладывает cookie сессии. Защита включена по умолчанию (токен в форме или заголовке). Для stateless API с токеном в заголовке Authorization её обычно выключают: браузер этот заголовок сам не подставит. Если аутентификация через cookie, CSRF выключать нельзя.
- CORS: браузер разрешает фронтенду с другого origin читать ответы, только если сервер вернул нужные заголовки. Настраивается
http.cors(...)иCorsConfigurationSource.allowedOrigins("*")вместе сallowCredentials(true)запрещено.
Частые ошибки
permitAllвыше правил с ограничениями или забытыйanyRequest().hasRoleпротивhasAuthorityи префиксROLE_.- Выключенный CSRF при cookie-аутентификации.
- Длинноживущие JWT без возможности отзыва, секреты в payload.
- Проверка прав только на фронтенде.
Что спросят на собесе
- Как запрос проходит через Spring Security? Что такое SecurityFilterChain?
- Аутентификация против авторизации, 401 против 403.
- Как хранить пароли?
- Как устроена проверка JWT в Resource Server, как отзывать токены?
- Что такое CSRF и когда его можно выключить? Чем CSRF отличается от CORS?