Hello World

Spring Security 源码学习(二): Spring Security自动配置(初始化流程)

【深度好文】: 「和耳朵」SpringSecurity是如何代理过滤器链的?

1. 自动配置security的bean信息

SpringBoot自动配置实现原理

下面是 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;
	}
}
posted @ 2022-05-18 19:51  小小忧愁米粒大  阅读(383)  评论(0编辑  收藏  举报
瞅啥瞅,好好看书