spring security 源码简单阅读(一)

本贴最后更新于 1785 天前,其中的信息可能已经沧海桑田

一、spring security 的三大配置

  • 我们配置 spring security 主要是通过继承 WebSecurityConfigurerAdapter 类来实现,其中主要有 3 个方法
    • configure(AuthenticationManagerBuilder auth),此方法用于设置用户的权限认证
    • configure(HttpSecurity http),此方法用于配置 http 协议,比如设置 session 管理,设置是否启用 CSRF 等
    • configure(WebSecurity web),此方法用于配置访问资源的限制,经常用来过滤静态资源的校验



二、启动流程

  • @EnableWebSecurity
    • 使用 @Import 实例化了类 WebSecurityConfiguration,该类主要做了以下两个工作
      • setFilterChainProxySecurityConfigurer 方法将我们自定义的配置信息存放在 webSecurity 对象中.
        webSecurity 其实就是一个 filter,但是需要通过调用 build 才能返回 filter
      • springSecurityFilterChain 方法为我们创建一个默认的 filter.
        当然如果我们自定义类继承了 WebSecurityConfigurerAdapter 就不会创建默认的



三、过滤器初始化

1、在阅读源码之前

在介绍过滤器的初始化之前我们先记住下面这个继承关系,便于后面的理解
image.png

  • SecurityBuilder 接口只有一个 build() 方法
  • AbstractSecurityBuilder 使用 CAS 保证 build() 方法的原子性,然后将真正的 build() 操作交给 doBuild()
  • AbstractConfiguredSecurityBuilder 实现 doBuild() 方法,定义了具体的步骤以及 build 的各个状态
  • WebSecurity 实现 performBuild() 来完成最终的真正的 build

这几个类就是设计模式中很典型的 模板模式

2、初始化过程

在之前的启动流程中我们说到 WebSecurityConfiguration 类的 springSecurityFilterChain 方法会为我们创建一个 filter,看一下代码:

@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();
}

在这个方法的最后一行,我们看到了调用了 build() 方法,这个方法就是过滤器初始化的入口了,build() 流程如下:

  • 执行父类 AbstractSecurityBuilderbuild()
  • 执行父类 AbstractConfiguredSecurityBuilderdoBuild()
  • 执行当前类也就是 WebSecurity 类的 performBuild()

现在我们来仔细看一看 WebSecurity 类的 performBuild() 方法具体做了些什么,源码:

protected Filter performBuild() throws Exception {
	// question 1:securityFilterChainBuilders是什么时候初始化的?
	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");
	// question 2:ignoredRequests什么时候初始化的?
	int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
			chainSize);
	// 将ignoredRequests和securityFilterChainBuilders中的元素封装一下,然后存放进securityFilterChains中
	for (RequestMatcher ignoredRequest : ignoredRequests) {
		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
	}
	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
		securityFilterChains.add(securityFilterChainBuilder.build());
	}
	// 代理securityFilterChains
	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);
	}
	postBuildAction.run();
	return result;
}
  • question 1
    • AbstractConfiguredSecurityBuilder#doBuild() -> AbstractConfiguredSecurityBuilder#init() -> WebSecurityConfigurerAdapter#init(..) -> WebSecurity#addSecurityFilterChainBuilder(..)
    • 最终在 addSecurityFilterChainBuilder 方法中初始化了 securityFilterChainBuilders,你要是问我 doBuild 方法又是哪来的,很简单之前就说过了,是 WebSecurity 的 build()调用的
  • question 2
    • IgnoredRequestConfigurer#mvcMatchers(..) -> WebSecurity#mvcMatchers(..)
    • 那系统是在何时使用过 IgnoredRequestConfigurer#mvcMatchers(..) 方法的呢?很简单
      我们在使用 spring security 的时候都会继承 WebSecurityConfigurerAdapter 类重新一些配置方法,其中有一个配置方法一般会如下使用:
      @Override
      public void configure(WebSecurity web) throws Exception {
          web.ignoring().mvcMatchers("/images/**");
          web.ignoring().mvcMatchers("/js/**");
          web.ignoring().mvcMatchers("/css/**");
          web.ignoring().mvcMatchers("/lib/**");
      // web.ignoring()方法只是返回内部类IgnoredRequestConfigurer的实例
      // 我们就是在这儿使用了IgnoredRequestConfigurer#mvcMatchers(..)
      }
      
  • 上面的这两个问题解决了,接着就是各种代理了,然后返回被代理的过滤器链

总结一下本方法的作用:就是找到我们配置或者默认配置的一些过滤器,然后代理封装一下,最后组成一个过滤器链再返回

参考

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
  • 代码
    466 引用 • 631 回帖 • 9 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...