Security Filter Chain là chuỗi servlet filter Spring Security đặt trước controller — mỗi filter xử lý 1 concern.
Thứ tự filter:
Request
→ SecurityContextHolderFilter (load SecurityContext)
→ UsernamePasswordAuthenticationFilter (form login)
→ BearerTokenAuthenticationFilter (JWT)
→ ExceptionTranslationFilter (→ 401/403)
→ AuthorizationFilter (authorization)
→ ControllerConfig custom (Spring Security 6):
java
@Bean
SecurityFilterChain chain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests(a -> a
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))
.build();
}Custom filter:
java
@Component
class RequestIdFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest req, ...) {
MDC.put("requestId", UUID.randomUUID().toString());
filterChain.doFilter(req, resp);
MDC.clear();
}
}Security Filter Chain is the chain of servlet filters Spring Security places before controllers — each filter handles one concern.
Filter order:
Request
→ SecurityContextHolderFilter (loads SecurityContext)
→ UsernamePasswordAuthenticationFilter (form login)
→ BearerTokenAuthenticationFilter (JWT)
→ ExceptionTranslationFilter (→ 401/403)
→ AuthorizationFilter (authorization)
→ ControllerCustom config (Spring Security 6):
java
@Bean
SecurityFilterChain chain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests(a -> a
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))
.build();
}Custom filter:
java
@Component
class RequestIdFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest req, ...) {
MDC.put("requestId", UUID.randomUUID().toString());
filterChain.doFilter(req, resp);
MDC.clear();
}
}