Spring Security 6: SecurityFilterChain и цепочка фильтров

Безопасность в Spring — это цепочка фильтров, через которую проходит каждый запрос до контроллера. В Spring Security 6 она настраивается бином SecurityFilterChain.
Суть: запрос проходит фильтры безопасности до контроллера. В Security 6 конфигурация — это @Bean SecurityFilterChain с лямбда-DSL; WebSecurityConfigurerAdapter удалён, antMatchers заменён на requestMatchers.

Spring Security защищает приложение, вставляя перед контроллерами цепочку фильтров. Каждый фильтр решает свою задачу: проверить аутентификацию, авторизацию, CSRF и так далее. Запрос либо проходит всю цепочку и доходит до контроллера, либо отсекается с 401/403.

Современная конфигурация (Security 6)

Важно: старый стиль с наследованием от WebSecurityConfigurerAdapter удалён. Теперь вы объявляете бин SecurityFilterChain:

import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .httpBasic(org.springframework.security.config.Customizer.withDefaults());
        return http.build();
    }
}

Это лямбда-DSL: каждая настройка — лямбда. requestMatchers (вместо устаревшего antMatchers) задаёт правила по путям: что открыто всем, что — только админам, что требует аутентификации.

Как работает под капотом

Запрос входит в FilterChainProxy и проходит фильтры по очереди. Один извлекает учётные данные, другой проверяет права на путь. Если правило не выполнено — цепочка прерывается с 401 (не аутентифицирован) или 403 (нет прав), и контроллер не вызывается.

  Запрос GET /api/admin/users
        |
        v
  Цепочка фильтров безопасности
   ┌──────────────────────────────────┐
   │ 1. аутентификация (кто ты?)       │
   │ 2. авторизация (что тебе можно?)  │
   │    путь /api/admin -> нужен ADMIN │
   └──────────────────────────────────┘
        |                |
   правила ok?        нет прав?
        |                |
        v                v
   Controller        403 Forbidden

Смоделируем цепочку фильтров и проверку правил:

# Цепочка фильтров безопасности: правила по путям
rules = [
    ("/api/public", "permitAll"),
    ("/api/admin", "ROLE_ADMIN"),
    ("/api", "authenticated"),
]

def authorize(path, user):
    for prefix, rule in rules:
        if path.startswith(prefix):
            if rule == "permitAll":
                return 200
            if user is None:
                return 401                      # не аутентифицирован
            if rule == "authenticated":
                return 200
            if rule.startswith("ROLE_") and rule[5:] not in user["roles"]:
                return 403                      # нет прав
            return 200
    return 200

admin = {"name": "root", "roles": ["ADMIN"]}
guest = {"name": "guest", "roles": ["USER"]}

print(authorize("/api/public/info", None))   # 200
print(authorize("/api/admin/users", guest))  # 403
print(authorize("/api/admin/users", admin))  # 200
print(authorize("/api/orders", None))        # 401

Нажмите «Попробуй сам ▶»: правила по путям дают 200/401/403 — ровно как делает цепочка фильтров Spring Security.

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

  • Искать WebSecurityConfigurerAdapter. Он удалён в Security 6 — используйте бин SecurityFilterChain.
  • antMatchers вместо requestMatchers. Старый метод переименован; туториалы с antMatchers устарели.
  • permitAll слишком широко. Лишний открытый путь — дыра в безопасности. Открывайте только нужное.

Best practices

  • Конфигурируйте через бин SecurityFilterChain и лямбда-DSL.
  • Закрывайте всё по умолчанию (anyRequest().authenticated()), открывайте точечно.
  • Для разных групп путей можно завести несколько бинов SecurityFilterChain.

Итог: Spring Security 6 — это цепочка фильтров, настраиваемая бином SecurityFilterChain с лямбда-DSL. Забудьте про WebSecurityConfigurerAdapter и antMatchers — это прошлое.

Проверьте себя
1. Как в Spring Security 6 настраивается безопасность вместо удалённого WebSecurityConfigurerAdapter?
AЧерез XML-файл
BОбъявлением @Bean SecurityFilterChain с лямбда-DSL и HttpSecurity
CЧерез аннотацию @Secure на контроллере
DНикак, безопасность включена всегда
2. Что заменило устаревший метод antMatchers в Spring Security 6?
ApathMatchers
BrequestMatchers
CurlMatchers
DantMatchers не менялся