从源码角度拆解SpringSecurity之核心流程

从源码角度拆解SpringSecurity系列文章

从源码角度拆解SpringSecurity之核心流程
从源码角度拆解SpringSecurity之万能的SecurityBuilder
从源码角度拆解SpringSecurity之勤劳的FilterChainProxy
从源码角度拆解SpringSecurity之C位的AuthenticationManager



前言

之前实现认证和权限控制,都是自己纯手写或者基于shiro框架来实现的,后来了解到spring security框架,相对来讲更适合spring项目的接入。可是spring security的接入配置比较难以理解,如果没有搞懂框架的底层细节,就更是云里雾里了。所以我专门花了几天的时间大概浏览了spring security的源码,大致搞清楚了框架的架构设计和业务流程,现写个系列文章做一个记录,已备后续自己翻阅,如有不当之处烦请指正。


注意

文章所摘源码版本为spring-boot-starter-security:5.0.6.RELEASEspring-security-oauth2:2.3.5.RELEASE


一、Spring Security是什么?

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements

以上是官方对于Spring Security框架的描述,简单翻译如下:
Spring Security是一个功能强大且高度自定义的认证和访问控制框架。它是Spring系列微服务应用中名副其实的安全框架解决标准。
Spring Security框架对于Java微服务应用而言是能同时提供认证和授权能力的。正如所有的Spring官方项目而言,它真正的魅力及强大之处在于它是一个极易扩展和自定义的安全框架。


二、Spring Security是怎么对请求进行“管控”的

总所周知Spring项目要进行权限控制一般都是基于Filter或者HandlerInterceptor,Spring Security框架自然也遵循Spring规范使用Filter来实现的。那么问题就来了,像我们注册Filter都是通过FilterRegistrationBean来注册到IoC的,形如:

@Configuration
public class FilterConfiguration {
    
    
    @Bean
    public FilterRegistrationBean<CustomFilter> registerCustomFilter() {
    
    
		FilterRegistrationBean<CustomFilter> bean = new FilterRegistrationBean<CustomFilter>();
        bean.setFilter(new CustomFilter());
        bean.setName("customFilter");
        bean.addUrlPatterns("/*");
        bean.setOrder(1);
        //do some other additional setting
        return bean;
	}
}

甚至如果不需要额外配置的话还可以直接将自定义的Filter进行注册,Spring Security也是直接注册的Filter。注册过程在WebSecurityConfiguration中,具体代码如下:

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

webSecurityConfigurers 是我们注册的几个配置类,直接数据来自

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

		Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);

		...
		
		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
    
    
			webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}

其中 @Value(xx) 是基于SpEL表达式,意思是调用 autowiredWebSecurityConfigurersIgnoreParents 这个bean的 getWebSecurityConfigurers 方法来进行获取,相关代码如下:

	public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
    
    
		List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
		Map<String, WebSecurityConfigurer> beansOfType = beanFactory
				.getBeansOfType(WebSecurityConfigurer.class);
		for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
    
    
			webSecurityConfigurers.add(entry.getValue());
		}
		return webSecurityConfigurers;
	}

无需解释了吧,就是简单中容器中获取类型为WebSecurityConfigurer的Bean。


三、Filter是如何被创建出来的

回顾上文,成员变量webSecurity的类型是WebSecurity,继承自AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> ,赋予的泛型值为 <Filter, WebSecurity> ,我们来看泛型解释

@param <O> The object that this builder returns
@param <B> The type of this builder (that is returned by the base class)

说明这个Builder要生成的对象是Filter负责生成该对象的是WebSecurity,接下来我们再来看看具体是如何生成的吧。
如上文所说,Filter是通过webSecurity.build() 生成的,WebSecurity继承自AbstractConfiguredSecurityBuilder,而AbstractConfiguredSecurityBuilder又继承自AbstractSecurityBuilder,其中build方法就定义在该类中,对应的方法内容如下:

	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");
	}

可以看到每个builder只能被执行一次build方法,执行时会进一步调用doBuild方法来进行生成,这个方法就是整个框架初始化的核心,定义在AbstractConfiguredSecurityBuilder当中

	@Override
	protected final O doBuild() throws Exception {
    
    
		synchronized (configurers) {
    
    
			buildState = BuildState.INITIALIZING;

			beforeInit();
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
			configure();

			buildState = BuildState.BUILDING;

			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

整个build过程分为四个阶段,分别是初始化、配置、构建、完毕,其中初始化和配置阶段就是遍历子configurers并依次进行初始化和配置,代码如下:

	//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);
		}
	}

	//configure方法
	private void configure() throws Exception {
    
    
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

		for (SecurityConfigurer<O, B> configurer : configurers) {
    
    
			configurer.configure((B) this);
		}
	}

	//getConfigurers方法
	private Collection<SecurityConfigurer<O, B>> getConfigurers() {
    
    
		List<SecurityConfigurer<O, B>> result = new ArrayList<SecurityConfigurer<O, B>>();
		for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {
    
    
			result.addAll(configs);
		}
		return result;
	}

其中getConfigurers的返回值是来自成员变量configurers,这里给大家留一个小疑问,这些configurers是怎样被添加进来的呢?
最后咱们很容易发现,要构建的对象其实是被performBuild创造出来的,那我们再来看看它又干了些什么吧。

	protected abstract O performBuild() throws Exception;

这是一个抽象方法,具体的实现需要子类来完成。这也不难理解,因为这是一个带泛型的抽象类,真正要构建什么只有具体实现的子类才能知道,那我们就来看看WebSecurity这个子类是如何实现的吧。

	@Override
	protected Filter performBuild() throws Exception {
    
    
		
		...
		
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		
		...

		Filter result = filterChainProxy;
		
		...
		
		return result;
	}

不难看出,实际上就是构建一个FilterChainProxy对象,所以我们整个Spring Security框架的拦截工作其实都交由这个勤劳的小蜜蜂来完成的。


至此整个初始化的核心流程就拆解完成了,下一篇我们将对框架配置部分的全能王SecurityBuilder展开说明。怎么样,你看懂了吗,有问题或者发现文章当中有谬误的地方,都欢迎留言评论哦。

转载请注明出处:从源码角度拆解SpringSecurity之核心流程

猜你喜欢

转载自blog.csdn.net/aa54682002/article/details/123792879