前言
Spring Security是一个优秀的安全管理框架,同时他很多地方支持可定制化。基于Spring Security,我们就可以做出供自己业务场景下的安全管理需求,例如在SaaS服务下的多租户权限控制。而Spring Security中最重要的实现方式,最重要的设计模式,那便非责任链模式莫属了。
配置初始化
在配置初始化前,都需要有一个机制来触发配置的初始化,道理很简单,因为我们不是所有场景下都需要用到Spring Security,只是在我们需要用到这个框架的时候,才需要去触发他。Spring Security对于这个的实现方式其实和大部分的框架都一样,便是使用注解的方式。
Spring Security中使用来@EnableWebSecurity
来触发配置的初始化,那为什么使用了这个注解就可以触发配置相关的代码运行呢?
里面用到的方式就是使用了@Import
注解,使用了这个注解,Spring就会把里面的两个类加载到Spring容器中,供Spring容器的调配。
这时候大家可能会有疑惑,我们平时不是使用@Autowired
,@Resource
来导入类的么,那是因为我们导入的是我们自己编写的类,一般是通过@ComponentScan(basePackages = {"XXX"})
来扫描到对应的包,在分析对应的包内的类中是否有@Autowired
,@Resource
这些注解,有这些注解就将这个类加载到容器中。但是框架中的类目录地址是多变的,我们可不能通过@ComponentScan(basePackages = {"XXX"})
这种方式来获取到对应类信息,所以一般使用注解方式,在注解中使用@Import
注解将对应的类加在到容器中。而且这个使用@Import
往往是配置类,也就是类上一般会加上@Configuration
,在类中就可以使用@Bean
来加载对应的bean到容器中了。
配置类的获取
配置类的获取是在WebSecurityConfiguration
中的setFilterChainProxySecurityConfigurer
类中,这里展示了@Value
的特殊用法,就是里面可以填写类的函数来获取对应的值,这个值就是对应的配置类。并且还创建了webSecurity
类,这个类可以用来配置类的执行,并最终生成springSecurityFilterChain,这个就是Spring Security 的责任链,终于看到标题对应的信息了有木有~
进入到这个函数中,可以看到获取到的就是在Spring容器中查找所有WebSecurityConfigurer
的实现类,但是配置类一般都有很多通用的方法,所以Spring Security创建一个适配类来配置不同的配置类实现,这个类是WebSecurityConfigurerAdapter
,因此我们如果想要实现自己的配置类,只需要自己实现WebSecurityConfigurerAdapter
基类即可,在Oauth2中便是使用了这种方式创建了ResourceServerConfiguration
等配置类。
责任链的生成
在回归回来,在使用@Import
注解导入的配置类中存在这个bean,这个bean中webSecurity.build()
函数就是配置的开启函数。其中webSecurity
的父类是AbstractConfiguredSecurityBuilder
,在配置类执行的过程中在这个类上执行了模板模式,可以看到
在执行上面模板函数是,这里有一个很好的设计思路
例如我们想要通过遍历来查找一个公司有多少人,此时有一个基类函数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
的父类,还是不知道的朋友可以往上再翻翻。
最后webSecurity
类的build()
函数返回结果可以得到List<SecurityFilterChain>
,这个就是过滤器链,但是如果我们手动遍历这个过滤器链,每一个调用其中的filter()
函数的话,体验感和设计上也并不是太好,Spring Security中创建了FilterChainProxy
类,这个类属性上有List<SecurityFilterChain>
,并提供一个filter功能,提供可以根据请求来获取不同的过滤器,来执行过滤。
对应代码如上,非常简单,我就不进行扩展讲解了。