网上一个比较好的图
由于是一个filterChain,因此如果我在FilterSecrutiyInterceptor,即最后一个过滤器上打断点,一定能够通过debug的方式来得到整个过滤器链条
在最后一个filter.doFilter方法上打一个断点,
得到整个filterChain,进一步验证了上面图的正确性。
但是这些filter是什么时候添加进去的呢?从security-start的自动配置类开始分析
@Import({ SpringBootWebSecurityConfiguration.class,
AuthenticationManagerConfiguration.class,
BootGlobalAuthenticationConfiguration.class, SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {
@EnableWebSecurity
public class SpringBootWebSecurityConfiguration {
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
这是配置类的入口类
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
if (previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException(
"@Order on WebSecurityConfigurers must be unique. Order of "
+ order + " was already used on " + previousConfig + ", so it cannot be used on "
+ config + " too.");
}
previousOrder = order;
previousConfig = config;
}
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
这个类的主要作用
1.1.1 构建WebSecurity对象
1.1.2 获得security相关的配置
- 通过这个调用BeanFactory中Bean的名字为autowiredWebSecurityConfigurersIgnoreParents的getWebSecurityConfigurers方法得到webSecurityConfigurers,并把这些配置加入到webSecurity对象中
通过debug可以看到有4个,
1. 自己定义的安全相关配置类
BrowserSecurityConfig
- security starter autoconfigure 自动注入的
SpringBootWebSecurityConfiguration$IgnoredPathsWebSecurityConfigurerAdapter
SpringBootWebSecurityConfiguration$ApplicationWebSecurityConfigurerAdapter- 用于管理的,暂时没看到在哪个地方注入的
ManagementWebSecurityAutoConfiguration$ManagementWebSecurityConfigurerAdapter
这个方法是个模板方法,定义了整个生成的骨架
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit();
//1.init,调用上面每个webSecurityConfigurers的init
init();
buildState = BuildState.CONFIGURING;
//2. 设置AuthenticationManager
beforeConfigure();
//3. 调用上面每个webSecurityConfigurers的configure方法
configure();
buildState = BuildState.BUILDING;
//4.生成filterChain
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
这样定义传入一个this,如果是http,就会传入httpsecurity的参数,如果是web就传入websecurity类型的参数,有点类似于策略模式
如何生成具体的filterChain,当然这是调用的是WebSecurity的方法,
protected Filter performBuild() throws Exception {
...
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
chainSize);
//1.首先添加不需要认证的url过滤器,这里面的url是静态资源文件目录
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
//2.添加需要经过安全认证的过滤器
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
//3.生成过滤器的代理
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
//4.真正的build方法执行
postBuildAction.run();
return result;
}
上面的分析是大概的整体flow,现拿一个做为例子:
这里使用的是模板方法设计模式
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
gethttp()->to create the http object and set the default param
@SuppressWarnings({ "rawtypes", "unchecked" })
protected final HttpSecurity getHttp() throws Exception {
if (http != null) {
return http;
}
//设置后置处理器?
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
.postProcess(new DefaultAuthenticationEventPublisher());
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
//获得AuthenticationManager
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
if (!disableDefaults) {
// @formatter:off
//添加一系列filter的默认配置
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
.logout();
// @formatter:on
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
}
}
//增加用户自定义的配置,重写这个方法,就会对上面的security chain进行添加或修改
configure(http);
return http;
}
关于泛型的声明
//声明
public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
//实例
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<CsrfConfigurer<H>, H> {
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter>
extends AbstractHttpConfigurer<T, B> {
protected Filter performBuild() throws Exception {
...
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
chainSize);
//1.首先添加不需要认证的url过滤器,这里面的url是静态资源文件目录
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
//2.添加需要经过安全认证的过滤器
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
//3.生成过滤器的代理
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
//4.真正的build方法执行
postBuildAction.run();
return result;
}
需要拿 到所有的securityFilterChainBuilder,即init中创建的httpSecurity对象,然后进行生成
可以看到这里有三个securityFilterChainBuilder,每个securityFilterChainBuilder里面包含configures,sharedObjects等对象
securityFilterChainBuilder.build就是根据这些配置文件来生成filter的,再次调用AbstractConfiguredSecurityBuilder#doBuild如果
BrowserSecurityConfig
//security starter autoconfigure 自动注入的
SpringBootWebSecurityConfiguration I g n o r e d P a t h s W e b S e c u r i t y C o n f i g u r e r A d a p t e r S p r i n g B o o t W e b S e c u r i t y C o n f i g u r a t i o n IgnoredPathsWebSecurityConfigurerAdapter SpringBootWebSecurityConfiguration IgnoredPathsWebSecurityConfigurerAdapterSpringBootWebSecurityConfigurationApplicationWebSecurityConfigurerAdapter
//用于管理的,暂时没看到在哪个地方注入的
ManagementWebSecurityAutoConfiguration M a n a g e m e n t W e b S e c u r i t y C o n f i g u r e r A d a p t e r / / s e c u r i t y s t a r t e r a u t o c o n f i g u r e 自 动 注 入 的 S p r i n g B o o t W e b S e c u r i t y C o n f i g u r a t i o n ManagementWebSecurityConfigurerAdapter //security starter autoconfigure 自动注入的 SpringBootWebSecurityConfiguration ManagementWebSecurityConfigurerAdapter//securitystarterautoconfigure自动注入的SpringBootWebSecurityConfigurationIgnoredPathsWebSecurityConfigurerAdapter
SpringBootWebSecurityConfiguration A p p l i c a t i o n W e b S e c u r i t y C o n f i g u r e r A d a p t e r / / 用 于 管 理 的 , 暂 时 没 看 到 在 哪 个 地 方 注 入 的 M a n a g e m e n t W e b S e c u r i t y A u t o C o n f i g u r a t i o n ApplicationWebSecurityConfigurerAdapter //用于管理的,暂时没看到在哪个地方注入的 ManagementWebSecurityAutoConfiguration ApplicationWebSecurityConfigurerAdapter//用于管理的,暂时没看到在哪个地方注入的ManagementWebSecurityAutoConfigurationManagementWebSecurityConfigurerAdapter
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
这里最主要的是getHttp这个方法,查看这个方法,发现构建了http请求,并且最后也调用了configure(http)来配置http
也就是说如果我们自定义的类重写了这个方法,那么就用的是我们自定义的。
Q:如果这里也调用了configure方法,那么上面那第三步的config方法是不是就没有必要调用了?是我自己理解有误吗?
A:的确是理解有误,所有的构建在init中即第1步已经完成了,第3步中的configure,
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
可以看到这里参数是泛型B,传递的是this对象,由开始知道,我们调用的是WebSecurity,而不是HttpSecurity对象,
因此这里调用 的下面这个方法,其实是个空方法(以前以为configure(HttpSecurity http)),
public void configure(WebSecurity web) throws Exception {
}
Q:按这个逻辑,最后执行performBuild,来构建整个filter链,没啥问题,
问题是这个方法中会调用
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
再次掉入了这个创建的循环中
A: AbstractConfiguredSecurityBuilder#configure
并未进入循环,这里的getConfigurres为null
最后一步的performBuild,调用的也是authenticationManagerBuilder#performBuild,并不是前面的performBuild
如果当前对象是httpSecurity,则调用所有configure方法,生成对应的filterchain
Q:哪里生成SecurityBuilder?
A:WebSecurityConfigurerAdapter#init方法中添加了,这里即HttpSecurity这个对象
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}