前言

Spring Security是一个优秀的安全管理框架,同时他很多地方支持可定制化。基于Spring Security,我们就可以做出供自己业务场景下的安全管理需求,例如在SaaS服务下的多租户权限控制。而Spring Security中最重要的实现方式,最重要的设计模式,那便非责任链模式莫属了。

配置初始化

在配置初始化前,都需要有一个机制来触发配置的初始化,道理很简单,因为我们不是所有场景下都需要用到Spring Security,只是在我们需要用到这个框架的时候,才需要去触发他。Spring Security对于这个的实现方式其实和大部分的框架都一样,便是使用注解的方式

Spring Security中使用来@EnableWebSecurity来触发配置的初始化,那为什么使用了这个注解就可以触发配置相关的代码运行呢?

Java aop责任链模式优雅实现 spring 责任链_spring


里面用到的方式就是使用了@Import注解,使用了这个注解,Spring就会把里面的两个类加载到Spring容器中,供Spring容器的调配。

这时候大家可能会有疑惑,我们平时不是使用@Autowired,@Resource来导入类的么,那是因为我们导入的是我们自己编写的类,一般是通过@ComponentScan(basePackages = {"XXX"})来扫描到对应的包,在分析对应的包内的类中是否有@Autowired,@Resource这些注解,有这些注解就将这个类加载到容器中。但是框架中的类目录地址是多变的,我们可不能通过@ComponentScan(basePackages = {"XXX"})这种方式来获取到对应类信息,所以一般使用注解方式,在注解中使用@Import注解将对应的类加在到容器中。而且这个使用@Import往往是配置类,也就是类上一般会加上@Configuration,在类中就可以使用@Bean来加载对应的bean到容器中了。

配置类的获取

Java aop责任链模式优雅实现 spring 责任链_后端_02


配置类的获取是在WebSecurityConfiguration中的setFilterChainProxySecurityConfigurer类中,这里展示了@Value的特殊用法,就是里面可以填写类的函数来获取对应的值,这个值就是对应的配置类。并且还创建了webSecurity类,这个类可以用来配置类的执行,并最终生成springSecurityFilterChain,这个就是Spring Security 的责任链,终于看到标题对应的信息了有木有~

Java aop责任链模式优雅实现 spring 责任链_初始化_03


进入到这个函数中,可以看到获取到的就是在Spring容器中查找所有WebSecurityConfigurer的实现类,但是配置类一般都有很多通用的方法,所以Spring Security创建一个适配类来配置不同的配置类实现,这个类是WebSecurityConfigurerAdapter,因此我们如果想要实现自己的配置类,只需要自己实现WebSecurityConfigurerAdapter基类即可,在Oauth2中便是使用了这种方式创建了ResourceServerConfiguration等配置类。

责任链的生成

Java aop责任链模式优雅实现 spring 责任链_spring_04

在回归回来,在使用@Import注解导入的配置类中存在这个bean,这个bean中webSecurity.build()函数就是配置的开启函数。其中webSecurity的父类是AbstractConfiguredSecurityBuilder,在配置类执行的过程中在这个类上执行了模板模式,可以看到

Java aop责任链模式优雅实现 spring 责任链_后端_05

在执行上面模板函数是,这里有一个很好的设计思路

Java aop责任链模式优雅实现 spring 责任链_初始化_06

例如我们想要通过遍历来查找一个公司有多少人,此时有一个基类函数AbstractClass,其中的query()是一个虚函数,对于公司,不能直接遍历里面的职工,但可以遍历公司下一个部门的职工,这时我们就可以这样实现,创建两个类,Staff和Department类都实现了基类

Class Department {
	private List<Staff> staffs;
	private Integer staffNum;

	@Overide
	public void query() {
		foreach(Staff staff: staffs) {
			stafff.query(staffNum);
		}
	}
}

Class Staff {
	@Overide
	public void query(Integer staffNum) {
		staffNum++;
	}
}

这样做的好处很明显,代码非常的好理解他的作用,并且实现起来也非常的简洁。

那为啥我要特意说一下这种方式,原因就是AbstractConfiguredSecurityBuilder中也是使用了这种方式,不要告诉我AbstractConfiguredSecurityBuilder类已经不知道是啥了哦,他就是WebSecurity的父类,还是不知道的朋友可以往上再翻翻。

Java aop责任链模式优雅实现 spring 责任链_spring_07


最后webSecurity类的build()函数返回结果可以得到List<SecurityFilterChain>,这个就是过滤器链,但是如果我们手动遍历这个过滤器链,每一个调用其中的filter()函数的话,体验感和设计上也并不是太好,Spring Security中创建了FilterChainProxy类,这个类属性上有List<SecurityFilterChain>,并提供一个filter功能,提供可以根据请求来获取不同的过滤器,来执行过滤。

Java aop责任链模式优雅实现 spring 责任链_初始化_08

对应代码如上,非常简单,我就不进行扩展讲解了。