I want to contribute to the great answers by including some code. There are three beans that are super important in Spring Security. based on their types they are DelegatingFilterProxy, FilterChainProxy and SecurityFilterChain.
DelegatingFilterProxy delegates the job of filtering requests to a bean of type FilterChainProxy which its name is springSecurityFilterChain, and FilterChainProxy is configured like this:
@Bean(
name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
return (Filter)this.webSecurity.build();
}
springSecurityFilterChain (or FilterChainProxy) itself has a list of SecurityFilterChain. SecurityFilterChain itself has a list of Filter instances that do the actual logic.
Every time we extend WebSecurityConfigurerAdapter and override the configure(HttpSecurity httpSecurity) method, we actually created a SecurityFilterChain that is going to be used by springSecurityFilterChain
How springSecurityFilterChain selects the appropriate SecurityFilterChain from the list? based on the boolean matches(HttpServletRequest request) method that is defined in the SecurityFilterChain interface.
So HttpSecurity is used to create a customized SecurityFilterChain.
Now when WebSecurity actually comes into play? WebSecurity actually allow us to customize springSecurityFilterChain(or FilterChainProxy). take a look at how springSecurityFilterChain is created.
It is the performBuild method of WebSecurity that is called for creating springSecurityFilterChain bean.
@Override
protected Filter performBuild() throws Exception {
Assert.state(
!securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke "
+ WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (debugEnabled) {
logger.warn("\n\n"
+ "********************************************************************\n"
+ "********** Security debugging is enabled. *************\n"
+ "********** This may include sensitive information. *************\n"
+ "********** Do not use in a production system! *************\n"
+ "********************************************************************\n\n");
result = new DebugFilter(filterChainProxy);
}
postBuildAction.run();
return result;
}
As you can see when Spring wants to registers SecurityFilterChain into springSecurityFilterChain bean for each web.ignoring().... Spring is going to add a DefaultSecurityFilterChain which is a custom implementation of SecurityFilterChain into the beginning of the list.
When a request comes along springSecurityFilterChain is going to check its list of SecurityFilterChain in order to delegate the filtering job to that SecurityFilterChain. springSecurityFilterChain is going to call match method of each SecurityFilterChain. if the request URL starts with "/resources/**" in your case Spring delegates the job of filtering request to an instance of DefaultSecurityFilterChain in the beginning of the list and our custom SecurityFilterChains which is added by this line:
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
completely ignored.