Springboot中SpringSecurity自动装配原理
(1)Springboot有一个自动配置类SecurityFilterAutoConfiguration,SecurityFilterAutoConfiguration只要当项目中引入了SpringSecurity的相关jar包就会被自动加载。装载这个类是干嘛的呢?
(2)如下图,SecurityFilterAutoConfiguration 自动配置类主要用于,当存在名字叫做"springSecurityFilterChain"的bean时,就会往容器中注入一个DelegatingFilterProxyRegistrationBean类对象。所以SecurityFilterAutoConfiguration类对象主要用于生成DelegatingFilterProxyRegistrationBean类对象。
那么名字叫做"springSecurityFilterChain"的bean是从哪里来的呢?我们先按下不表,我们先看下这个DelegatingFilterProxyRegistrationBean类对象是干嘛的。
(3)通过下图的继承关系,我们可以看到DelegatingFilterProxyRegistrationBean类继承了RegistrationBean类,而RegistrationBean类实现了ServletContextInitializer接口。
(ServletContextInitializer是springboot内置tomcat时,tomcat初始化后会在TomcatStarter的onStartup方法中调用所有实现了ServletContextInitializer接口的onStartup方法。
和这个类似的是WebApplicationInitializer,WebApplicationInitializer是外置tomcat时,tomcat初始化后会调用程序的SpringServletContainerInitializer类的onStartup,而在onStartup方法中会调用所有实现了WebApplicationInitializer接口的onStartup方法
其实就是tomcat初始化后要调用一个类,然后在这个类中调用程序中某个接口所有实现类的onStartup方法进行处理。
)
也就是当servlet容器创建成功后,会自动执行DelegatingFilterProxyRegistrationBean类的onStartup方法。那么它是做了什么操作呢?
(4)通过调式可以追踪到核心的方法链,onStartup()->register()->addRegistration()->getFilter(),最终getFilter()获得的过滤器注册到了servlet容器中。需要注意的是上面一系列方法有些是DelegatingFilterProxyRegistrationBean从父类继承过来的,有些是自己重写的。
也就是说DelegatingFilterProxyRegistrationBean类的作用是注册了一个过滤器。这个过滤器其实是DelegatingFilterProxy的匿名类。
(5)既然DelegatingFilterProxy是过滤器,那么肯定要看它在doFilter()方法做了什么。
通过上面的源码,我们可以知道,doFilter()中主要是获取了一个过滤器对象delegateToUse,然后调用了delegateToUse的doFilter()方法。下面我们看看initDelegate()方法获得的是一个怎么样的过滤器对象。
可以看到initDelegate()方法中,从spring容器中获取了一个名叫this.getTargetBeanName()的过滤器对象,而this.getTargetBeanName()其实就是我们一开始的"springSecurityFilterChain"。
那么DelegatingFilterProxy类的作用其实就是执行到它时,暂停原有的过滤器链,先执行名叫"springSecurityFilterChain"过滤器的doFilter()方法。
总结上面几步:
SecurityFilterAutoConfiguration自动装配为了注入DelegatingFilterProxyRegistrationBean类,DelegatingFilterProxyRegistrationBean类为了向servlet容器注册DelegatingFilterProxy过滤器,DelegatingFilterProxy过滤器中执行名叫"springSecurityFilterChain"的过滤器。
需要注意的是以上的其实都是在springboot中的类,而名叫"springSecurityFilterChain"的过滤器其实是在SpringSecurity中。也就是说上面绕了一大圈,其实目的就是为了实现你引入SpringSecurity的依赖,springboot将SpringSecurity中的过滤器加入到项目中来,而你却什么都不用配置。
(6)名叫"springSecurityFilterChain"的过滤器对象到底是哪里来的?
通过断点可以看到SpringSecurity包中有一个WebSecurityConfiguration类中注入了名叫"springSecurityFilterChain"的FilterChainProxy类对象。我们对FilterChainProxy干嘛的先按下不表,WebSecurityConfiguration又是什么时候注入的呢?要知道WebSecurityConfiguration是在SpringSecurity包中的,我们在项目中又没有主动创建过。
(7)在SpringSecurity的配置包下有一个 @EnableWebSecurity,在该注解上通过@Import引入了上面的WebSecurityConfiguration类,也就是说我想在我项目中使用SpringSecurity,应该需要在项目中添加@EnableWebSecurity,但是为什么我没加也能使用?
(8)大家回头看下(1)中自动装配的SecurityFilterAutoConfiguration,它的类上有一个@AutoConfigureAfter(SecurityAutoConfiguration.class)注解,也就是springboot在这之前会装置一个SecurityAutoConfiguration类。
而SecurityAutoConfiguration类上,通过@Import引入了四个类,而 @EnableWebSecurity就在其中的SpringBootWebSecurityConfiguration或WebSecurityEnablerConfiguration头上(根据版本有关)
以上总结:->表示右边类通过左边类引入到程序中
第一条线为了创建SpringSecurity的过滤器链(对应上面的6-8步):自动装配了SecurityAutoConfiguration类->@EnableWebSecurity注解->WebSecurityConfiguration类->FilterChainProxy对象(名叫“springSecurityFilterChain”)
第二条线为了将SpringSecurity过滤器链插入到servlet过滤器链中(对应上面的1-5布):对应之前的总结。
也就是现在,引入了SpringSecurity后,当有请求到来时,就会触发FilterChainProxy的doFilter()。
(9)FilterChainProxy虽然自己是过滤器,但是通过名字也不难看出,它同时是过滤器链的代理,也就是在该类中保存了SpringSecurity一系列的过滤器链。
如下图源码,FilterChainProxy的doFilter()中调用了doFilterInternal()方法,
而doFilterInternal()获取了本次请求路径相关的过滤器,然后组合成一个过滤器链,最后调用这个过滤器链。
也就是说FilterChainProxy的作用是根据请求路径选择过滤器,将选择的过滤器组合成一个过滤器链。然后执行这条过滤器链。
以上便是SpringSecurity的自动装配原理了。欢迎交流。