Careeroza
DelegatingFilterProxy and FilterChainProxy
Bridging Tomcat and Spring
Tomcat creates servlet filters itself and knows nothing about Spring beans. DelegatingFilterProxy is the bridge: Tomcat calls it, and it looks up the bean named springSecurityFilterChain (a FilterChainProxy) in the Spring context and delegates to it. Spring Boot registers all of this automatically.
Tomcat --> DelegatingFilterProxy --(bean lookup)--> FilterChainProxy
|
+-----------------+-----------------+
| |
chain 1: /api/** chain 2: any request
(stateless, HTTP Basic) (form login, sessions)
first chain whose securityMatcher matches the request winsMultiple Chains
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
@Order(1) // checked first
SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**") // this chain only handles /api/**
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.csrf(csrf -> csrf.disable());
return http.build();
}
@Bean
@Order(2) // everything else: the web pages
SecurityFilterChain webChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin(Customizer.withDefaults());
return http.build();
}
}- The chain without
securityMatchermatches everything, so it must have the highest@Ordernumber (checked last). FilterChainProxyuses only one chain per request: the first match.- Why it is useful: APIs want stateless 401 responses, browsers want login pages and redirects.
FilterChainProxy Extras
Because every security request passes through one bean, FilterChainProxy also does housekeeping: it clears the SecurityContextHolder after each request (so a user never leaks into the next request on the same thread) and applies the HttpFirewall, which rejects malicious URLs such as /api/../admin or paths with encoded slashes.
The Firewall at Work
curl -i "localhost:8080/api/products/..;/admin"Example output
HTTP/1.1 400 The request was rejected because the URL contained a potentially malicious String ";"