spring security加载原理(基于springboot)
一、基本架構
二、自動配置原理
依據 Spring Boot 自動配置原理,其會自動加載spring-boot-autoconfigure.jar中/META-INF/spring.factories內鍵值org.springframework.boot.autoconfigure.EnableAutoConfiguration指定的自動配置類。查看該文件,可以看到,與 Spring Security 相關的自動配置類有如下幾個:
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, \ org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration, \ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration, \ org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration, \ org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration, \ org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration, \ org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration, \ org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration, \ org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration, \ org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration, \ org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration, \每個配置類都為 Spring Security 注入不同的 Bean 到 Spring容器中。這里我們著重介紹一下SecurityFilterAutoConfiguration和SecurityAutoConfiguration配置類,因為這兩個配置類會自動裝配DelegatingFilterProxy和FilterChainProxy到 Spring容器中。
三、自動裝配FilterChainProxy
下面介紹下配置類SecurityAutoConfiguration,具體如下:
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(DefaultAuthenticationEventPublisher.class) @EnableConfigurationProperties(SecurityProperties.class) @Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,SecurityDataConfiguration.class }) public class SecurityAutoConfiguration {@Bean@ConditionalOnMissingBean(AuthenticationEventPublisher.class)public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {return new DefaultAuthenticationEventPublisher(publisher);} }可以看到:
SecurityAutoConfiguration導入了3個配置類
查看WebSecurityEnablerConfiguration配置類,其源碼如下:
@Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(name = "springSecurityFilterChain") @ConditionalOnClass(EnableWebSecurity.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @EnableWebSecurity class WebSecurityEnablerConfiguration { }當 Spring容器中沒有名稱為springSecurityFilterChain的 Bean 等條件時,就會加載該配置類,此時@EnableWebSecurity注解生效:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,HttpSecurityConfiguration.class }) @EnableGlobalAuthentication @Configuration public @interface EnableWebSecurity {boolean debug() default false; }- SpringWebMvcImportSelector的作用是判斷當前的環境是否包含springmvc,因為springsecurity可以在非spring環境下使用,為了避免DispatcherServlet的重復配置,所以使用了這個注解來區分。
- WebSecurityConfiguration顧名思義,是用來配置web安全的,下面的小節會詳細介紹。
- OAuth2ImportSelector:該類是為了對 OAuth2.0 開放授權協議進行支持。ClientRegistration 如果被引用,具體點也就是 spring-security-oauth2 模塊被啟用(引入依賴jar)時。會啟用 OAuth2 客戶端配置 OAuth2ClientConfiguration
- HttpSecurityConfiguration會通過@Autowired去獲取容器中的一個AuthenticationManager實例,如果沒能獲取到則使用依賴注入的AuthenticationConfiguration實例創建一個AuthenticationManager實例,這個實例其實就是ProviderManager。
注解@EnableWebSecurity又導入了4個配置類,這里著重看下
WebSecurityConfiguration:
@Configuration(proxyBeanMethods = false) public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {.../*** Creates the Spring Security Filter Chain* @return the {@link Filter} that represents the security filter chain* @throws Exception*/@Bean(name = "springSecurityFilterChain")public Filter springSecurityFilterChain() throws Exception {...return this.webSecurity.build();}... }可以看到:
WebSecurityConfiguration#springSecurityFilterChain()最終生成了一個名稱為springSecurityFilterChain的Bean 實體,該 Bean 的實際類型其實為FilterChainProxy,是由WebSecurity#build()方法創建的。
綜上,SecurityAutoConfiguration配置類生成了很多 Bean 實體,其中最重要的一個是名稱為springSecurityFilterChain的FilterChainProxy對象。
注意:WebSecurityEnablerConfiguration 目的僅僅就是在某些條件下激活 @EnableWebSecurity 注解
再看一下@ConditionalOnDefaultWebSecurity
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional({DefaultWebSecurityCondition.class}) public @interface ConditionalOnDefaultWebSecurity { } class DefaultWebSecurityCondition extends AllNestedConditions {DefaultWebSecurityCondition() {super(ConfigurationPhase.REGISTER_BEAN);}@ConditionalOnMissingBean({WebSecurityConfigurerAdapter.class, SecurityFilterChain.class})static class Beans {Beans() {}}@ConditionalOnClass({SecurityFilterChain.class, HttpSecurity.class})static class Classes {Classes() {}} }可以看到,當:
- 條件一 classpath中存在 SecurityFilterChain.class, HttpSecurity.class
- 條件二 沒有自定義 WebSecurityConfigurerAdapter.class, SecurityFilterChain.class
就會引入默認的DefaultWebSecurityCondition。
四、自動裝配DelegatingFilterProxy
下面介紹下配置類SecurityFilterAutoConfiguration,其源碼如下所示:
@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties({SecurityProperties.class}) @ConditionalOnClass({AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class}) @AutoConfigureAfter({SecurityAutoConfiguration.class}) public class SecurityFilterAutoConfiguration {private static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";public SecurityFilterAutoConfiguration() {}@Bean@ConditionalOnBean(name = {"springSecurityFilterChain"})public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean("springSecurityFilterChain", new ServletRegistrationBean[0]);registration.setOrder(securityProperties.getFilter().getOrder());registration.setDispatcherTypes(this.getDispatcherTypes(securityProperties));return registration;}private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {return securityProperties.getFilter().getDispatcherTypes() == null ? null : (EnumSet)securityProperties.getFilter().getDispatcherTypes().stream().map((type) -> {return DispatcherType.valueOf(type.name());}).collect(Collectors.toCollection(() -> {return EnumSet.noneOf(DispatcherType.class);}));} }可以看到,要加載SecurityFilterAutoConfiguration前,必須先加載配置類SecurityAutoConfiguration,該配置類前面已經詳細介紹了,主要功能就是注入了一個名稱為springSecurityFilterChain的 Bean,因此,此時SecurityFilterAutoConfiguration#securityFilterChainRegistration就會生效,最終生成一個DelegatingFilterProxyRegistrationBean實體。DelegatingFilterProxyRegistrationBean實現了ServletContextInitializer接口,當系統執行ServletWebServerApplicationContext.selfInitialize()進行初始化時,會依次調用到:
RegistrationBean.onStartup() --> DynamicRegistrationBean.register()
–> AbstractFilterRegistrationBean.addRegistration()
其中,AbstractFilterRegistrationBean#addRegistration()源碼如下:
protected Dynamic addRegistration(String description, ServletContext servletContext) {Filter filter = this.getFilter();return servletContext.addFilter(this.getOrDeduceName(filter), filter); }this.getFilter()實際調用的是DelegatingFilterProxyRegistrationBean#getFilter()方法,其內部會創建一個DelegatingFilterProxy實例并返回,源碼如下:
public DelegatingFilterProxy getFilter() {return new DelegatingFilterProxy(this.targetBeanName, this.getWebApplicationContext()) {protected void initFilterBean() throws ServletException {}}; }因此,AbstractFilterRegistrationBean#addRegistration()最終就是通過ServletContext#addFilter將一個DelegatingFilterProxy實例注入到 Servlet 的FilterChain中。
- DelegatingFilterProxy和SecurityFilterChain的關系
請求進來經由 DelegatingFilterProxy 可以分發到不同的SecurityFilterChain進行授權驗證
- 示意圖,當DelegatingFilterProxy注入到FileterChain后,就可以攔截每一個請求,對其做出認證和授權了
五、默認加載的Filter
1. WebAsyncManagerIntegrationFilter 支持集成Spring的異步調用 2. SecurityContextPersistenceFilter 從Session中獲取SecurityContext,沒有則新建,最終放入SecurityContextHolder中。 3. HeaderWriterFilter 往響應對象response中寫入Header屬性(Like X-Frame-Options, X-XSS-Protection and X- Content-Type-Options) 4. CsrfFilter csrf校驗 5. LogoutFilter 默認攔截[POST]/logout 處理登出邏輯 6. UsernamePasswordAuthenticationFilter 默認攔截[POST]/login 處理登錄認證邏輯6.1 第一步 封裝Authentication(從request中獲取認證信息封裝為UsernamePasswordAuthenticationToken)6.2 第二步 獲取AuthenticationManager實例[ProviderManager]6.3 第三步 ProviderManager基于委托者模式通過AuthenticationProvider列表完成認證6.4 第四步 認證通過后,將Authentication放入SecurityContextHolder的SecurityContext中。 7. DefaultLoginPageGeneratingFilter 默認攔截[GET]/login 生成登錄頁面 8. DefaultLogoutPageGeneratingFilter 默認攔截[POST]/login 生成登出頁面 9. BasicAuthenticationFilter 認證Basic [Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==] 10. RequestCacheAwareFilter 用于用戶登錄成功后,重新恢復因為登錄被打斷的請求 11. SecurityContextHolderAwareRequestFilter 包裝request實現servlet api的一些接口方法isUserInRole、getRemoteUser 12. AnonymousAuthenticationFilter 匿名用戶認證、信息填充 13. SessionManagementFilter Session管理 14. ExceptionTranslationFilter 異常處理 15. FilterSecurityInterceptor 權限校驗、未登錄攔截、無權限攔截總結
以上是生活随笔為你收集整理的spring security加载原理(基于springboot)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020中国淘宝村研究报告
- 下一篇: 互联网日报 | 爱奇艺会员宣布11月13