Spring Security是一个全面的、高度可定制的安全框架,专为Java应用程序设计,旨在提供身份验证和授权功能,确保应用的安全性。它源自Acegi Security项目,后被整合进Spring生态系统并更名。该框架利用Spring AOP(面向切面编程)和Servlet过滤器来实施安全控制,支持多种安全策略和认证机制。
再高版本的Spring Security中将授权功能进行了提取,形成了一个独立项目spring-authorization-server。所以使用高版本时需要注意该变化,避免引入的依赖缺少。
1.Spring Security整体工作流程
Spring Security是基于过滤器来进行认证和授权的,那么其工作的位置在哪里呢,具体如下图所示:
由上图可知DelegatingFilterProxy是Spring Framework和Spring Security之间建立联系的桥梁。通过DelegatingFilterProxy来引入Spring Security所定义的一系列过滤器。那么DelegatingFilterProxy是如何起到承上启下的呢?
2.DelegatingFilterProxy
从名字上看就知道其是一个代理,那么该代理是何时绑定到Tomcat中的Context组件上进而被servlet匹配到,又是如何调用Spring Security中的FilterChainProxy?这一步骤离不开Spring Boot的自动装配,其引入了一个SecurityFilterAutoConfiguration自动配置类,在该配置类中帮我们创建了DelegatingFilterProxy,具体如下:
再将调用该ServletContextInitializer接口时会调用DelegatingFilterProxyRegistrationBean的getFilter方法,将我们的DelegatingFilterProxy进而绑定到context组件中,进而匹配何时的servlet。 至于RegistrationBean何时调用初始化的本文章不做过多介绍,感兴趣的可以看一下:深入源码解析:Spring Boot 如何加载 Servlet 、Filter 与 Listener-CSDN博客
接下来继续看一下DelegatingFilterProxy是如何调用到Spring Security中的过滤器的,这里的重点是传入的targetBeanName(springSecurityFilterChain),具体如下:
那么问题来了,beanName为springSecurityFilterChain的过滤器是如何初始化的呢?这就离不开Spring Security的初始化流程。
3.Spring Security的初始化流程
经过上面的1,2步之后,我们明白了Spring Security的大体工作流程,那么接下来我们将从源码的层面来探究一下Spring Security的初始化流程。这离不开一个注解即@EnableWebSecurity(注意:高版本之后不管是资源端还是客户端还是授权服务端,均使用该注解)。其具体如下:
WebSecurityConfiguration类的主要作用是通过WebSecurity来构建生成springSecurityFilterChain对应的bean对象,即FilterChainProxy。
HttpSecurityConfiguration类的主要作用是通过HttpSecurity来构建生成httpSecurity对象。而httpSecurity对象的作用就是帮我们创建DefaultSecurityFilterChain来填充FilterChainProxy对象中的List<SecurityFilterChain> filterChains集合。
1.WebSecurityConfiguration
该类在生成bean对象时,属性填充阶段会调用如下方法:
SecurityFilterChain类型的bean对象不知道大家是否看着比较眼熟,不眼熟的朋友可以看下图,获取会勾起你的记忆:
看到上图之后,小伙伴们是不是有一丝丝的熟悉感,所以在WebSecurityConfiguration bean对象创建的过程会先调用我们自定义的SecurityFilterChain bean对象的创建工作。
不知道大家有没有注意上图方法中的参数信息是HttpSecurity对象,也就是说我们自定义的SecurityFilterChain bean对象再实例化之前,会先从IOC容器中获取HttpSecurity类型的对象进行注入,那么HttpSecurity对象的生成又是再哪里呢?那就需要我们的HttpSecurityConfiguration闪亮登场。
2.HttpSecurityConfiguration
该类的作用很简单,主要是帮我们创建原型的HttpSecurity对象,为什么是原型的呢,因为再Spring Security中可以存在多条执行链SecurityFilterChain,而HttpSecurity的作用就是通过建造者模式帮我们创建一个个的SecurityFilterChain。其具体源码如下:
从上图可以看出注入的HttpSecurity其实已经帮我们进行了很多默认配置。
我们继续看一下securityFilterChain(HttpSecurity http)方法,我们往HttpSecurity对象中增加了很多属性信息,包括我们的拦截路径信息,还有需要哪些过滤器信息。这些信息是如何添加到目标过滤器呢,我们不防拿出一个配置信息进行研究,如下图:
我们通过上面的方式引入了oauth2的过滤器,那是如何引入的呢,继续往下:
帮我们往HttpSecurity对象中增加了一些配置类,这些配置类均实现了SecurityConfigurer中的init和config方法,然后将配置类放入到HttpSecurity对象的父类AbstractConfiguredSecurityBuilder的configurers属性中。
然后继续看一下http.build()方法,其底层调用doBuild()方法,如下图:
比如我们看一下OAuth2LoginConfigurer,其源码如下:
我们继续看一下performBuild()方法,如下:
经过上面的处理,那么在WebSecurityConfiguration类中的securityFilterChains属性,便被填充了我们自定义的DefaultSecurityFilterChain,里面只有两个属性,一个是路径匹配器,一个是匹配之后执行的过滤器链。
3.springSecurityFilterChain bean对象的创建
该对象的构建还需要回到WebSecurityConfiguration类,具体如下:
接着继续看一下this.webSecurity.build()方法,底层调用了doBuild方法,具体如下:
继续看一下performBuild()方法,具体如下:
这样的话我们就返回了一个beanName为springSecurityFilterChain的FilterChainProxy,该对象中的List<SecurityFilterChain> filterChains属性就封装着我们在配置类自定义的一个过滤器执行链,且每个过滤器中都封装了我们自定义的一些配置信息。
至此整个初始化流程就已经完成,然后结合最开始的整体流程图,就能整体串起来。
如果您希望更深入地学习Spring Security源码,我强烈推荐您访问以下项目链接:https://gitee.com/chengyadong555/spring-security.git 。在这个项目中,您将发现对Spring Security源码的逐行分析,作者不仅提供了丰富的注释,还融入了自己独到的理解和见解。