ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2022-05-18 20:01:24  阅读:232  来源: 互联网

标签:springSecurityFilterChain Spring Filter 源码 delegate servletContext Security null


【深度好文】: 「和耳朵」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;
	}
}

标签:springSecurityFilterChain,Spring,Filter,源码,delegate,servletContext,Security,null
来源: https://www.cnblogs.com/virgosnail/p/16283454.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有