在上一篇中我们梳理了spring security 是怎样一步步调用到过滤器链的,下面我们来看下框架是怎么构造过滤器链的,以及过滤器链中主要的过滤器
1.过滤器链的构造
1.1自动配置
springboot 从2.7开始需要被自动加载的类要写在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里,每一行为配置类的全类名,为了向下兼容目前springboot还支持原来的spring.factories配置,但是打开spring.factories文件看里面的配置很少了已经大部分被移到了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中我们可以看到如下和spring security相关自动配置:

其中有一条配置为org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,我们看下SecurityAutoConfiguration的源码如下:
在类中通过使用@EnableConfigurationProperties注解读取配置,并使用@Import导入其他配置
@AutoConfiguration
@ConditionalOnClass({DefaultAuthenticationEventPublisher.class})
@EnableConfigurationProperties({SecurityProperties.class})
@Import({SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class})
public class SecurityAutoConfiguration {
public SecurityAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean({AuthenticationEventPublisher.class})
public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
return new DefaultAuthenticationEventPublisher(publisher);
}
}
进入导入的SpringBootWebSecurityConfiguration中源码(因为源码太长,有减缩)如下:
可见在SpringBootWebSecurityConfiguration类中使用了@EnableWebSecurity注解,该注解为springsecurity的启用注解,这就是为啥我们只需要引入pom依赖,不需要任何配置就会自动启用springsecurity的原因。
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
class SpringBootWebSecurityConfiguration {
SpringBootWebSecurityConfiguration() {
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean(
name = {"springSecurityFilterChain"}
)
@ConditionalOnClass({EnableWebSecurity.class})
@EnableWebSecurity
static class WebSecurityEnablerConfiguration {
WebSecurityEnablerConfiguration() {
}
}
....
进入EnableWebSecurity 源码如下,可见在类中同样使用了@Import注解来导入其他配置
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, HttpSecurityConfiguration.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
进入 源码 我们可以看到注入springSecurityFilterChain
@Configuration(
proxyBeanMethods = false
)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
......
@Bean(
name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
Assert.state(!hasConfigurers || !hasFilterChain, "Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
if (!hasConfigurers && !hasFilterChain) {
WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
Iterator var7 = this.securityFilterChains.iterator();
while(true) {
while(var7.hasNext()) {
SecurityFilterChain securityFilterChain = (SecurityFilterChain)var7.next();
this.webSecurity.addSecurityFilterChainBuilder(() -> {
return securityFilterChain;
});
Iterator var5 = securityFilterChain.getFilters().iterator();
while(var5.hasNext()) {
Filter filter = (Filter)var5.next();
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor)filter);
break;
}
}
}
var7 = this.webSecurityCustomizers.iterator();
while(var7.hasNext()) {
WebSecurityCustomizer customizer = (WebSecurityCustomizer)var7.next();
customizer.customize(this.webSecurity);
}
return (Filter)this.webSecurity.build();
}
}
......
下面我们看下springSecurityFilterChain怎么构建的,进入最后一行(Filter)this.webSecurity.build()方法,源码如下:
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
private AtomicBoolean building = new AtomicBoolean();
private O object;
public AbstractSecurityBuilder() {
}
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = this.doBuild();
return this.object;
} else {
throw new AlreadyBuiltException("This object has already been built");
}
}
public final O getObject() {
if (!this.building.get()) {
throw new IllegalStateException("This object has not been built");
} else {
return this.object;
}
}
protected abstract O doBuild() throws Exception;
}
我们看出在build方法中调用了doBuild()抽象方法,我们再看下这个方法的 实现
protected final O doBuild() throws Exception {
synchronized(this.configurers) {
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
this.beforeInit();
this.init();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
this.beforeConfigure();
this.configure();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
O result = this.performBuild();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;
return result;
}
}
在doBuild的实现方法中,我们看到了调用this.performBuild()方法下面我们进入this.performBuild()源码
protected Filter performBuild() throws Exception {
Assert.state(!this.securityFilterChainBuilders.isEmpty(), () -> {
return "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. Typically this is done by exposing a SecurityFilterChain bean. More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly";
});
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList(chainSize);
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList();
Iterator var4 = this.ignoredRequests.iterator();
while(var4.hasNext()) {
RequestMatcher ignoredRequest = (RequestMatcher)var4.next();
this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest + ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest, new Filter[0]);
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries.add(this.getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
var4 = this.securityFilterChainBuilders.iterator();
while(var4.hasNext()) {
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder = (SecurityBuilder)var4.next();
//为每个httpSecurity生成一条过滤器链
SecurityFilterChain securityFilterChain = (SecurityFilterChain)securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries.add(this.getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
if (this.privilegeEvaluator == null) {
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(requestMatcherPrivilegeEvaluatorsEntries);
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (this.debugEnabled) {
this.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);
}
this.postBuildAction.run();
return (Filter)result;
}