Spring Security 源码学习(二): Spring Security自动配置(初始化流程)
【深度好文】: 「和耳朵」SpringSecurity是如何代理过滤器链的?
1. 自动配置security的bean信息
下面是 Spring Boot autoconfigure 自动创建的配置类信息
2. springSecurityFilterChain 初始化
1. springSecurityFilterChain 定义
WebSecurityConfiguration中定义了 springSecurityFilterChain 这个bean
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
}
2. springSecurityFilterChain 初始化
待补充
3. springSecurityFilterChain 如何被添加到Filter
创建一个 targetBeanName 属性值为 springSecurityFilterChain 的 DelegatingFilterProxy Filter 实例, 并注册到 ServletContext
1. AbstractSecurityWebApplicationInitializer
public abstract class AbstractSecurityWebApplicationInitializer
implements WebApplicationInitializer {
public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";
public final void onStartup(ServletContext servletContext) {
beforeSpringSecurityFilterChain(servletContext);
if (this.configurationClasses != null) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(this.configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootAppContext));
}
if (enableHttpSessionEventPublisher()) {
servletContext.addListener(
"org.springframework.security.web.session.HttpSessionEventPublisher");
}
servletContext.setSessionTrackingModes(getSessionTrackingModes());
insertSpringSecurityFilterChain(servletContext);
afterSpringSecurityFilterChain(servletContext);
}
/**
* 创建一个 DelegatingFilterProxy 实例注册 Filter
*/
private void insertSpringSecurityFilterChain(ServletContext servletContext) {
String filterName = DEFAULT_FILTER_NAME;
DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
filterName);
String contextAttribute = getWebApplicationContextAttribute();
if (contextAttribute != null) {
springSecurityFilterChain.setContextAttribute(contextAttribute);
}
registerFilter(servletContext, true, filterName, springSecurityFilterChain);
}
/**
* 将 DelegatingFilterProxy 添加到 ServletContext 的 Filter中
*/
private void registerFilter(ServletContext servletContext,
boolean insertBeforeOtherFilters, String filterName, Filter filter) {
Dynamic registration = servletContext.addFilter(filterName, filter);
if (registration == null) {
throw new IllegalStateException(
"Duplicate Filter registration for '" + filterName
+ "'. Check to ensure the Filter is only configured once.");
}
registration.setAsyncSupported(isAsyncSecuritySupported());
EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters,
"/*");
}
}
4. springSecurityFilterChain 如何工作
DelegatingFilterProxy 在请求第一次到来时初始化, 从应用中获取bean名称为 springSecurityFilterChain 的实例, 然后调用 springSecurityFilterChain 的 doFilter 方法
public class DelegatingFilterProxy extends GenericFilterBean {
@Nullable
private String targetBeanName;
@Nullable
private volatile Filter delegate;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 懒加载,使用时进行初始化
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
// 初始化 delegate
synchronized (this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
// 调用 springSecurityFilterChain 的 doFilter()
invokeDelegate(delegateToUse, request, response, filterChain);
}
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
String targetBeanName = getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
// 根据 bean 名称获取实例对象
Filter delegate = wac.getBean(targetBeanName, Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
}
如果文章对您有所帮助,可以点一下推荐