Spring Security是一个强大的并且高度可定制化的访问控制框架。 它基于spring应用。
Spring Security是聚焦于为java应用提供授权和验证的框架。像所有的spring项目一样,Spring Security真正的强大在于可以非常简单的拓展功能来实现自定义的需求。
在分析SpringBoot集成的SpringSecurity源码时,一般可以分为两部分来分析Spring安全框架的源码。
一、SpringSecurity在SpringBoot框架的启动过程中的加载过程。
二、SpringSecurity在请求执行过程当中的执行过程。
现在我根据上面的两个过程对SpringSecurity的源码进行分析。
在分析时我们需要在springboot项目中引入SpringSecurity的maven依赖配置。该配置如下所示:
<!--spring 安全框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
注意:我分析的springsecurity版本是5.0.7-RELEASE
SpringSecurity在SpringBoot框架的启动过程中的加载过程。
SpringSecurity框架在调用过程中通过配置的方式往spring容器中注入很多bean,为调用过程中做准备。
在SpringSecurity中存在很多配置类,负责在springboot启动时往容器注入bean。本文主要分析一下设计注入的类。
在SpringSecurity框架中有三个非常核心的类和接口,分别是
1.SecurityFilterChain接口
2.FilterChainProxy类
3.DelegatingFilterProxy类
这个三个接口和类的相互之间的步骤关系如下:
第一步:生成一个FilterChainProxy类型的对象,其中的属性filterChains是SecurityFilterChain类型的List集合,该对象是一个被spring容器管理名称为springSecurityFilterChain类型为FilterChainProxy的bean。
第二步:生成一个DelegatingFilterProxy类型的对象,将beanName即springSecurityFilterChain作为DelegatingFilterProxy类型对象属性targetBeanName的值,供后面请求时获取bean。这样FilterChainProxy类型的对象就被DelegatingFilterProxy类型的对象委托管理了。
DelegatingFilterProxy对象的生成是tomcat启动过程中会调用所有继承了RegistrationBean类的
onStartUp方法,最终调用了实现类中的addRegistration方法。RegistrationBean类中onStartUp方法的调用逻辑可以参考我写的springMvc分析第一章
SpringMvc源码分析(一):启动tomcat服务器,加载DispatcherServlet并将DispatcherServlet纳入tomcat管理_xl649138628的博客-CSDN博客
其调用链路是
+RegistrationBean#onStartup
+DynamicRegistrationBean#register
+AbstractFilterRegistrationBean#addRegistration(往StandardContext设置拦截器类型为DelegatingFilterProxy)
+DelegatingFilterProxyRegistrationBean#getFilter()
第三步:前端发起请求时,调用了DelegatingFilterProxy类型的拦截器执行doFilter方法。doFilter方法获取被委托的对象FilterChainProxy并调用其doFilter方法。FilterChainProxy的doFilter方法,执行获取到的所有的拦截器然后再获取代理对象执行容器加载时保存的拦截器再执行。
本文主要分析第一步和第二步。
1.生成一个FilterChainProxy类型的对象
1.1分析配置文件并生成beanName为springSecurityFilterChain的Bean
1.1.1 SpringSecurity拦截器示意图
在SpringSecurity官方文档中可以看到如下示意图。
该图中清楚的可以看到请求访问时,DelegatingFilterProxy管理FilterChainProxy,FilterChainProxy里调用SecurityFilterChain类型的过滤器。
下面我会详细的分析这三个类和对象是怎么关联起来 。
1.1.2 安全框架的配置类及如何加载
在springboot启动过程中会获取spring.factories配置文件里的配置类并加载到spring容器中,观察spring.factories配置文件里的配置内容,涉及到springsecurity的如下图红框处所示。
我们首先关注SecurityAutoConfiguration和SecurityFilterAutoConfiguration这两个配置类。
深入分析这些类,我们可以看到配置类的关系如下图所示:
1.1.3配置类是如何获取到 springSecurityFilterChain这个bean的
首先分析SecurityAutoConfiguration配置类
@Configuration
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
//导入属性配置文件,内部声明了user类
@EnableConfigurationProperties(SecurityProperties.class)
//导入并加载下面三个配置类到Spring容器管理
@Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,
SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {
//发布认证事件,当AuthenticationEventPublisher bean不存在时加载
@Bean
@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
public DefaultAuthenticationEventPublisher authenticationEventPublisher(
ApplicationEventPublisher publisher) {
//内部实现就是spring的ApplicationEventPublisher,
// 用于springsecurity各种权限时间的交互,如登陆失败,会发布一个事件,
// 然后通知其它组件做出相应的响应
return new DefaultAuthenticationEventPublisher(publisher);
}
}
分析该配置类里导入的三个配置类SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,SecurityDataConfiguration.class
1.SpringBootWebSecurityConfiguration配置类
作用是WebSecurityConfigurerAdapter 类存在但是bean对象不存在时注册默认的WebSecurityConfigurerAdapter 类型是DefaultConfigurerAdapter的bean。
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
public class SpringBootWebSecurityConfiguration {
//往容器中注入WebSecurityConfigurerAdapter类型的Bean,后面的逻辑会使用
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER)
static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
}
}
2.WebSecurityEnablerConfiguration配置类
该类文件如下,可以看到其中声明了@EnableWebSecurity注解
//WebSecurityConfigurerAdapter bean对象存在
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
//没有名称为springSecurityFilterChain的bean
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {
}
进入@EnableWebSecurity注解
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
/**
* Controls debugging support for Spring Security. Default is false.
* @return if true, enables debug support with Spring Security
*/
boolean debug() default false;
}
可以看到引入了WebSecurityConfiguration和SpringWebMvcImportSelector两个配置类,声明了@EnableGlobalAuthentication注解。先研究WebSecurityConfiguration类
2.1WebSecurityConfiguration类
类中的英文注释如下:
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
* based security for Spring Security. It then exports the necessary beans. Customizations
* can be made to {@link WebSecurity} by extending {@link WebSecurityConfigurerAdapter}
* and exposing it as a {@link Configuration} or implementing
* {@link WebSecurityConfigurer} and exposing it as a {@link Configuration}. This
* configuration is imported when using {@link EnableWebSecurity}.
意思是:基于SpringSecurity框架的安全性执行web使用WebSecurity去创建一个FilterChainProxy。然后输出需要的bean.通过继承WebSecurityConfigurerAdapter并且声明为一个Configuration配置或者继承WebSecurityConfigurer并且声明为一个Configuration配置来实现定制化。这个WebSecurityConfiguration类是通过EnableWebSecurity注解引入的。
分析WebSecurityConfiguration类重点关注以下代码
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) { //注意hasConfigurers为true,此部分逻辑不执行
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
//往AbstractConfiguredSecurityBuilder类型对象的configurers属性
//(该属性是LinkedHashMap类型)中添加了一个WebSecurityConfigurerAdapter类型的数据
webSecurity.apply(adapter);
}
return webSecurity.build();
}
该端代码往spring容器中注入了一个名称为springSecurityFilterChain的bean。
1.1.4分析springSecurityFilterChain,并分析springSecurityFilterChain是如何获取到过滤器并管理过滤器的
再源码中可以看到这段代码
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { });
该代码是通过 objectObjectPostProcessor调用的,objectObjectPostProcessor对象是通过
@Autowired(required = false)
private ObjectPostProcessor<Object> objectObjectPostProcessor;
注入到WebSecurityConfiguration配置类对象里的。objectObjectPostProcessor这个bean是通过@EnableWebSecurity注解里的@EnableGlobalAuthentication里的引入的AuthenticationConfiguration.class里引入的ObjectPostProcessorConfiguration.class注入的。注入代码如下:
@Configuration
public class ObjectPostProcessorConfiguration {
@Bean
public ObjectPostProcessor<Object> objectPostProcessor(
AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
继续回到objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { });方法。因为objectObjectPostProcessor是AutowireBeanFactoryObjectPostProcessor类型的,所以调用的是AutowireBeanFactoryObjectPostProcessor的postProcess方法。
在postProcess方法的源码中,可以看到其将传入的对象生成一个bean并注入到spring容器中。
由于这个对象是new WebSecurityConfigurerAdapter()生成的,所以生成的是一个WebSecurityConfigurerAdapter类型的bean。
public <T> T postProcess(T object) {
if (object == null) {
return null;
}
T result = null;
try {
result = (T) this.autowireBeanFactory.initializeBean(object,
object.toString());
}
catch (RuntimeException e) {
Class<?> type = object.getClass();
throw new RuntimeException(
"Could not postProcess " + object + " of type " + type, e);
}
this.autowireBeanFactory.autowireBean(object);
if (result instanceof DisposableBean) {
this.disposableBeans.add((DisposableBean) result);
}
if (result instanceof SmartInitializingSingleton) {
this.smartSingletons.add((SmartInitializingSingleton) result);
}
return result;
}
继续分析springSecurityFilterChain方法里的webSecurity.apply(adapter)方法。我们发现webSecurity对象的赋值是在以下源码中实现的
@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));
if (debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
//根据继承WebSecurityConfigurer配置类的@Order注解进行排序
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);
}
//将自定义继承了WebSecurityConfigurer的配置类集合赋值给webSecurityConfigurers属性
this.webSecurityConfigurers = webSecurityConfigurers;
}
在上面的代码中我们发现入参
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers
这段代码的意思是调用autowiredWebSecurityConfigurersIgnoreParents对象里的getWebSecurityConfigurers方法。autowiredWebSecurityConfigurersIgnoreParents对象是通过WebSecurityConfiguration类里的以下方法注入的。
@Bean
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
ConfigurableListableBeanFactory beanFactory) {
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
观察AutowiredWebSecurityConfigurersIgnoreParents类里的getWebSecurityConfigurers方法。
该方法的作用是获取WebSecurityConfigurer类型的bean。并返回一个list集合。该bean对象是开发者自定义的各种各样继承自WebSecurityConfigurerAdapter的配置类。如果开发者没有自定义任何配置类,那么这里获取到的就是前面所讲的SpringBootWebSecurityConfiguration 类中提供的默认配置类,将获取到的所有配置类实例放入webSecurityConfigurers集合中并返回。
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory
.getBeansOfType(WebSecurityConfigurer.class);
//循环将所有的过滤器放到webSecurityConfigurers属性中。
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
另外一个入参ObjectPostProcessor<Object> objectPostProcessor 该对象是Spring注入的AutowireBeanFactoryObjectPostProcessor的bean.该bean的生成在上文有分析过。
webSecurity = objectPostProcessor .postProcess(new WebSecurity(objectPostProcessor));
该段代码生成了一个WebSecurity 类型的bean并对WebSecurityConfiguration类的webSecurity属性赋值。
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
在上面的代码中循环获取到的自定义配置类。看见如下代码
public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
add(configurer);
return configurer;
}
重点关注上面add方法,源码如下:
private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
Assert.notNull(configurer, "configurer cannot be null");
Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
.getClass();
synchronized (configurers) {
if (buildState.isConfigured()) {
throw new IllegalStateException("Cannot apply " + configurer
+ " to already built object");
}
List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
.get(clazz) : null;
if (configs == null) {
configs = new ArrayList<SecurityConfigurer<O, B>>(1);
}
configs.add(configurer);
//给configurers属性里放入以类名为Key,List<SecurityConfigurer<O, B>>为value
//放入List<SecurityConfigurer<O, B>>里的是开发的自定义拦截器
this.configurers.put(clazz, configs);
if (buildState.isInitializing()) {
this.configurersAddedInInitializing.add(configurer);
}
}
}
这样所有的开发自定义的继承自WebSecurityConfigurer的配置类和SpringBootWebSecurityConfiguration配置类中通过@Bean方式纳入Spring容器管理的继承自WebSecurityConfigurer的WebSecurityConfigurerAdapter类都放到了AbstractConfiguredSecurityBuilder类的configurers属性中供后面调用。
即configurers属性值 = 开发自定的继承自WebSecurityConfigurer配置类+SpringBootWebSecurityConfiguration配置类导入的WebSecurityConfigurerAdapter类。
1.2 分析FilterChainProxy类型的代理对象是如何生成的,并且是如何管理springSecurityFilterChain 这个bean的。
继续分析springSecurityFilterChain方法里的webSecurity.build()方法。在前面我们知道了webSecurity对象是WebSecurity类型的。
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
//关注此方法
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
//待实现方法
beforeInit();
//调用的是AbstractConfiguredSecurityBuilder类里的init方法
init();
buildState = BuildState.CONFIGURING;
//待实现方法
beforeConfigure();
//调用的是AbstractConfiguredSecurityBuilder类里的configure方法
configure();
buildState = BuildState.BUILDING;
//调用的是WebSecurity类里的performBuild方法。
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
其中init方法调用了开发者自定义的实现了WebSecurityConfigurer
的配置类里的init方法及WebSecurityConfigurerAdapter类里的init方法。
以下是
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
public void init(final WebSecurity web) throws Exception {
//生成一个HttpSecurity类型的对象
final HttpSecurity http = getHttp();
//addSecurityFilterChainBuilder对securityFilterChainBuilders属性赋值
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
getHttp方法用于生成一个HttpSecurity类型的对象。
protected final HttpSecurity getHttp() throws Exception {
if (http != null) {
return http;
}
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
.postProcess(new DefaultAuthenticationEventPublisher());
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
if (!disableDefaults) {
// @formatter:off
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<>()).and()
.logout();
// @formatter:on
ClassLoader classLoader = this.context.getClassLoader();
//SpringFactoriesLoader类的主要作用是通过类路径下的META-INF/spring.factories文件
//获取工厂类接口的实现类,初始化并保存在缓存中,以供Springboot启动过程中各个阶段的调用。
//SpringFactoriesLoader.loadFactories():是根据参数factoryClass获取spring.factories下配置的所有实现类实例,返回List<T>的。
//SpringFactoriesLoader.loadFactoryNames():是根据参数factoryClass获取spring.factories下配置
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
//将所有AbstractHttpConfigurer类型的对象放入到AbstractConfiguredSecurityBuilder类的configurers属性中供后面调用
for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
}
}
//配置HttpSecurity类型对象的属性
configure(http);
return http;
}
其中configure方法调用了开发者自定义的继承自WebSecurityConfigurerAdapter的配置类里的configure方法
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
其中performBuild调用的是WebSecurity类里的performBuild方法,该方法的作用是FilterChainProxy类型的代理对象,该代理对象将拦截器链纳入代理对象管理。
@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));
}
//securityFilterChainBuilders取到的是HttpSecurity类型的对象
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
//重点关注此处,将拦截器链纳入filterChainProxy代理类管理,如果不扩展securityFilterChainBuilders属性,里面只有一个对象时HttpSecurity类型的。
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);
}
//执行WebSecurityConfigurerAdapter类init方法里传入的 run方法,该方法用于
//给filterSecurityInterceptor属性赋值
postBuildAction.run();
返回的是FilterChainProxy 类型的对象
return result;
}
这样 springSecurityFilterChain这个Bean名实际上对应的是FilterChainProxy 类型的对象。
2. 生成一个DelegatingFilterProxy类型的对象.
分析spring.factories配置文件里的配置类SecurityFilterAutoConfiguration。
可以看到如下源码:
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
//加载SecurityProperties配置类
@EnableConfigurationProperties(SecurityProperties.class)
//AbstractSecurityWebApplicationInitializer和SessionCreationPolicy存在再执行配置
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class,
SessionCreationPolicy.class })
//在SecurityAutoConfiguration加载完后再执行配置
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class SecurityFilterAutoConfiguration {
//省略。。。。。
}
在该配置类中通过@Bean的方式往spring容器中注入了一个bean,该bean的类型是 DelegatingFilterProxyRegistrationBean。
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
SecurityProperties securityProperties) {
//初始化对象,并对属性targetBeanName赋值为springSecurityFilterChain
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
查看DelegatingFilterProxyRegistrationBean的继承实现树,发现该类实现了RegistrationBean。RegistrationBean中有一个onStartup方法,在SpringBoot启动的过程中,tomcat容器会调用该方法。
在onStartUp方法中存在register,根据动态绑定机制执行的是DynamicRegistrationBean里的register方法。该register方法里调用了addRegistration方法。该addRegistration方法是一个抽象方法。调用的是AbstractFilterRegistrationBean里的addRegistration方法。
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = getFilter();
return servletContext.addFilter(getOrDeduceName(filter), filter);
}
在AbstractFilterRegistrationBean中getFilter是调用的DelegatingFilterProxyRegistrationBean里的getFilter方法。在该方法中this.targetBeanName属性值是springSecurityFilterChain字符串。
@Override
public DelegatingFilterProxy getFilter() {
return new DelegatingFilterProxy(this.targetBeanName,
getWebApplicationContext()) {
@Override
protected void initFilterBean() throws ServletException {
// Don't initialize filter bean on init()
}
};
}
分析getFilter方法该方法最终返回了一个DelegatingFilterProxy类型的对象。继续分析AbstractFilterRegistrationBean里的addRegistration方法。在addRegistration里执行完getFilter方法后,程序继续执行了servletContext.addFilter(getOrDeduceName(filter), filter)这段代码。在这段代码中
@Override
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = getFilter();
return servletContext.addFilter(getOrDeduceName(filter), filter);
}
一、servletContext是Tomcat里的ApplicationContextFacade类型的对象。
public ServletContext getServletContext() {
if (context == null) {
context = new ApplicationContext(this);
if (altDDName != null)
context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
}
return (context.getFacade());
}
二、ApplicationContextFacade通过addFilter方法往Tomcat的Servlet里添加了拦截器。这样拦截器就被Tomcat管理了。
@Override
public FilterRegistration.Dynamic addFilter(String filterName,
Filter filter) {
if (SecurityUtil.isPackageProtectionEnabled()) {
return (FilterRegistration.Dynamic) doPrivileged("addFilter",
new Class[]{String.class, Filter.class},
new Object[]{filterName, filter});
} else {
//设置的filterName为springSecurityFilterChain,即FilterChainProxy类型
return context.addFilter(filterName, filter);
}
}