Ответ
В Spring Security фильтры Servlet образуют цепочку, которая обрабатывает каждый HTTP-запрос до того, как он достигнет контроллера. Они отвечают за аутентификацию, авторизацию, защиту от атак и другую сквозную логику.
Ключевые встроенные фильтры:
SecurityContextPersistenceFilter: ВосстанавливаетSecurityContext(информацию об аутентификации) из сессии между запросами.UsernamePasswordAuthenticationFilter: Обрабатывает форму логина (POST/login).BasicAuthenticationFilter: Обрабатывает HTTP Basic Authentication.FilterSecurityInterceptor: Принимает окончательное решение о доступе к защищенному ресурсу на основе конфигурации (authorizeRequests()).
Создание и регистрация кастомного фильтра:
- Реализация фильтра: Наследуйтесь от
OncePerRequestFilter, чтобы гарантировать однократное выполнение за запрос.@Component public class CustomLoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { long startTime = System.currentTimeMillis(); // Логика ДО прохождения запроса дальше по цепочке filterChain.doFilter(request, response); // Пропускаем запрос дальше // Логика ПОСЛЕ прохождения цепочки (когда ответ уже сформирован) long duration = System.currentTimeMillis() - startTime; logger.info("Request {} completed in {} ms", request.getRequestURI(), duration); } } -
Встраивание в цепочку Security: Укажите позицию фильтра относительно других.
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private CustomLoggingFilter customLoggingFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .addFilterBefore(customLoggingFilter, UsernamePasswordAuthenticationFilter.class) // .addFilterAfter(filter, existingFilterClass) // .addFilterAt(filter, existingFilterClass) // заменяет позицию .authorizeRequests() // ... остальная конфигурация return http.build(); } }Почему это важно: Понимание цепочки фильтров позволяет правильно добавлять логирование, проверку заголовков, кастомную аутентификацию (например, по JWT) и другие cross-cutting concerns.
Ответ 18+ 🔞
А, слушай, смотри, вот эта вся ваша Spring Security, она там внутри, блядь, как матрёшка, сука, только из фильтров! Представь себе конвейер, ёпта, на заводе. Запрос приходит — и его по цепочке начинают пинать, как мячик, от одного фильтра к другому, пока он до контроллера не доползёт, весь измученный.
Эти, блядь, главные надзиратели на конвейере:
SecurityContextPersistenceFilter: Этот чувак — как охранник на проходной с фотографией. Ты утром пришёл, он тебя по пропуску узнал, и весь день ты по заводу ходишь, и он тебя не трогает. Он из сессии достаёт твойSecurityContext(кто ты и на что имеешь право) и суёт тебе его в карман на каждый запрос.UsernamePasswordAuthenticationFilter: А это, сука, тот самый дядька в отделе кадров, где ты форму заполняешь. POST на/loginприлетел — он тебя за шиворот: «Логин-пароль, быстро!». Проверит — и пропустит дальше, уже с бейджиком.BasicAuthenticationFilter: Это если ты не через форму, а сразу с порога орёшь «Я Вася!» и суёшь под нос свою базовую авторизацию в заголовках. Он тебя тоже опознает, но с меньшим энтузиазмом.FilterSecurityInterceptor: Ну а это, блядь, начальник цеха, последняя инстанция. Запрос уже почти у ресурса, а этот выходит: «Стоять! А по какому праву?». Смотрит в свои правила (authorizeRequests()), и если прав нет — пиздык дверью перед носом. До контроллера запрос может так и не дойти, застряв на этой мудозвонской проверке.
Хочешь своего охранника на конвейер поставить? Легко!
- Сделай фильтр: Главное — наследуйся от
OncePerRequestFilter, чтобы твой охранник не взбесился и не проверял одного и того же чела по десять раз за смену.@Component public class CustomLoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { long startTime = System.currentTimeMillis(); // Тут можешь что-то сделать ДО того, как запрос пойдёт по цепочке дальше filterChain.doFilter(request, response); // Это как крикнуть "Следующий!" на конвейере // А тут — логика ПОСЛЕ, когда ответ уже почти готов. Идеально, чтобы засечь, сколько всё длилось, ебать. long duration = System.currentTimeMillis() - startTime; logger.info("Запрос {} обработан за {} мс", request.getRequestURI(), duration); } } -
Встрой его в очередь: А то он встанет не в ту очередь и всех обоссёт. Нужно указать, перед кем или после кого он должен работать.
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private CustomLoggingFilter customLoggingFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // Вот, например, поставим нашего логгера ПЕРЕД тем фильтром, что логины проверяет .addFilterBefore(customLoggingFilter, UsernamePasswordAuthenticationFilter.class) // Можно и .addFilterAfter (после какого-то), или .addFilterAt (вместо, но осторожно, ёпта!) .authorizeRequests() // ... ну и дальше твои правила кто куда может return http.build(); } }
А нахуя это всё понимать? Да затем, сука, что без этого ты как слепой котёнок! Хочешь логировать все запросы? Добавляй свой фильтр. Нужно JWT-токен из заголовка выковыривать и юзера авторизовывать? Фильтр тебе в помощь. Защита от каких-нибудь ебучих атак? Опять фильтры! Это ж, блядь, фундамент, на котором вся эта security-хуиcurity держится. Не разберёшься — так и будешь тыкаться палкой в конфигурацию, надеясь на авось.