В асинхронных или веб-сервисах на реактиве нужно быть осторожным…
В асинхронных или веб-сервисах на реактиве нужно быть осторожным: SecurityContext не “переходит” автоматически в новые потоки. Для этого используют SecurityContextRepository и специальные методы в WebFlux.
⚠️ Важно: не храните SecurityContext в сессии, если у вас stateless-приложение (REST API). Вместо сессии используйте JWT или OAuth 2.0.
🧠 5. Авторизация: FilterSecurityInterceptor & AccessDecisionManager
FilterSecurityInterceptor запускается в конце цепочки фильтров и проверяет доступ к URL. Он запрашивает у SecurityMetadataSource список необходимых ролей для данного эндпоинта (Spring на основании @PreAuthorize, HttpSecurity конфигурации или XML). Затем передаёт дело в AccessDecisionManager (по умолчанию AffirmativeBased), который опрашивает список AccessDecisionVoter (например, RoleVoter для проверок ролей, WebExpressionVoter для SpEL).
Если хотя бы один голос “grant”, AffirmativeBased отпускает запрос (по умолчанию). Можно менять стратегию на Consensus или Unanimous.
💡 Трюк: чтобы локально протестировать SecurityContext, можно в тестах использовать аннотацию @WithMockUser(roles = "ADMIN") и проверять, что нужный эндпоинт доступен.
🧠 6. Аннотации & Method Security
Помимо URL-уровня, есть методная проверка:
* 📌 @PreAuthorize / @PostAuthorize / @Secured / @RolesAllowed — все используют тот же механизм Voter’ов, но проверяют уже на методах сервиса.
* 💡 Совет: включайте методную безопасность только там, где действительно нужна тонкая грануляция.
🧠 7. Хранение паролей & PasswordEncoder
С Java 17+ используйте PasswordEncoder с алгоритмами Argon2 или BCrypt:
⚠️ Никогда не храните пароли в открытом виде и не используйте MD5/SHA-1 — они считаются небезопасными.
🧠 8. Stateless vs Stateful
* Stateful (Сессии): Spring создаёт HTTP-сессию, а SecurityContextPersistenceFilter хранит контекст в сессии. Удобно для монолитов с классическим web-приложением.
* Stateless (JWT/OAuth2): убираем SessionCreationPolicy.STATELESS, используем BearerTokenAuthenticationFilter, аутентификация и авторизация проверяются по JWT в каждом запросе.
💡 Современный стек (Spring Boot 3+):
1. Настраиваем SecurityFilterChain с oauth2ResourceServer().jwt().
2. Подключаем spring-boot-starter-oauth2-resource-server.
3. Указываем issuer-uri или jwk-set-uri в application.yml.
🧠 9. Подпись запросов & CSRF
* По умолчанию CSRF включён для “форменных” запросов (POST, PUT, DELETE). Для stateless-API его обычно отключают:
⚠️ Внимание: не отключайте CSRF, если ваше приложение использует сессии и cookie на фронтенде!
💡 Совет по отладке: включите логирование фильтров:
logging.level.org.springframework.security=DEBUG
Тогда в логах вы увидите, как проходит запрос через каждый фильтр и где происходит отказ.
👉 @BookJava
⚠️ Важно: не храните SecurityContext в сессии, если у вас stateless-приложение (REST API). Вместо сессии используйте JWT или OAuth 2.0.
🧠 5. Авторизация: FilterSecurityInterceptor & AccessDecisionManager
FilterSecurityInterceptor запускается в конце цепочки фильтров и проверяет доступ к URL. Он запрашивает у SecurityMetadataSource список необходимых ролей для данного эндпоинта (Spring на основании @PreAuthorize, HttpSecurity конфигурации или XML). Затем передаёт дело в AccessDecisionManager (по умолчанию AffirmativeBased), который опрашивает список AccessDecisionVoter (например, RoleVoter для проверок ролей, WebExpressionVoter для SpEL).
FilterSecurityInterceptor
└─> SecurityMetadataSource (что нужно: ROLE_ADMIN)
└─> AccessDecisionManager.vote()
├─ RoleVoter.vote() → совпадает?
└─ WebExpressionVoter.vote() → SpEL-выражения?Если хотя бы один голос “grant”, AffirmativeBased отпускает запрос (по умолчанию). Можно менять стратегию на Consensus или Unanimous.
💡 Трюк: чтобы локально протестировать SecurityContext, можно в тестах использовать аннотацию @WithMockUser(roles = "ADMIN") и проверять, что нужный эндпоинт доступен.
🧠 6. Аннотации & Method Security
Помимо URL-уровня, есть методная проверка:
@EnableMethodSecurity // (Spring Boot 3+) вместо @EnableGlobalMethodSecurity
public class SecurityConfig { ... }
// Где-то в сервисе:
@PreAuthorize("hasRole('ADMIN') and #id == principal.id")
public void deleteUser(Long id) { ... }* 📌 @PreAuthorize / @PostAuthorize / @Secured / @RolesAllowed — все используют тот же механизм Voter’ов, но проверяют уже на методах сервиса.
* 💡 Совет: включайте методную безопасность только там, где действительно нужна тонкая грануляция.
🧠 7. Хранение паролей & PasswordEncoder
С Java 17+ используйте PasswordEncoder с алгоритмами Argon2 или BCrypt:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
⚠️ Никогда не храните пароли в открытом виде и не используйте MD5/SHA-1 — они считаются небезопасными.
🧠 8. Stateless vs Stateful
* Stateful (Сессии): Spring создаёт HTTP-сессию, а SecurityContextPersistenceFilter хранит контекст в сессии. Удобно для монолитов с классическим web-приложением.
* Stateless (JWT/OAuth2): убираем SessionCreationPolicy.STATELESS, используем BearerTokenAuthenticationFilter, аутентификация и авторизация проверяются по JWT в каждом запросе.
💡 Современный стек (Spring Boot 3+):
1. Настраиваем SecurityFilterChain с oauth2ResourceServer().jwt().
2. Подключаем spring-boot-starter-oauth2-resource-server.
3. Указываем issuer-uri или jwk-set-uri в application.yml.
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://keycloak.example.com/realms/myrealm🧠 9. Подпись запросов & CSRF
* По умолчанию CSRF включён для “форменных” запросов (POST, PUT, DELETE). Для stateless-API его обычно отключают:
http.csrf().disable();
* Если используете формы, не забудьте добавить в шаблон:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>⚠️ Внимание: не отключайте CSRF, если ваше приложение использует сессии и cookie на фронтенде!
💡 Совет по отладке: включите логирование фильтров:
logging.level.org.springframework.security=DEBUG
Тогда в логах вы увидите, как проходит запрос через каждый фильтр и где происходит отказ.
👉 @BookJava
Просмотры: 16