1. 程式人生 > >SpringSecurity源碼解讀

SpringSecurity源碼解讀

就是 @override 前言 project nco com ron ger new

1.前言

官方解釋如下

Spring Security is a powerful and highly customizable authentication and access-control framework. 
It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authorization to Java applications.
Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements.

https://spring.io/projects/spring-security

SpringSecurity項目繼承WebSecurityConfigurerAdapter完成攔截鑒權邏輯,如下

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(
"/", "/home").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Autowired public void
configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("USER"); } }

Spring鑒權認證思路就是利用J2EE的Filter,上面的WebSecurityConfigurerAdapter大量的configure操作,最終目的就是為了創建一個FilterChainProxy(bean‘s name: springSecurityFilterChain)實例。

為了分析SpringSecurity框架原理,本文帶大家追溯源碼,分析springSecurityFilterChain的定義初始化過程。

1.啟動入口

J2EE定義了javax.servlet.ServletContainerInitializer接口,就是為了替換以前普通的web項目的web.xml功能,使用者可以使用ServletContainerInitializer和SPI完成servlet/filter/listener定義,可以看官方文檔定義。

Spring Framework定義了SpringServletContainerInitializer類和WebApplicationInitializer接口,SpringBoot也定義了函數接口org.springframework.boot.web.servlet.ServletContextInitializer,兩者功能類似,都是替換web.xml定義使用的,但是SpringBoot新定義類可以解決war包的沖突問題,場景如:

假如項目pay-web打包為pay-web.war,pay-web.war同時包含了SpringBoot和SpringFramework相關類,但pay-web.war只用到SpringFramework的特性,跑在Tomcat容器。

容器在加載SpringFramework的SpringServletContainerInitializer,會默認尋找類路徑所有的WebApplicationInitializer實現類,這個SpringBoot的starter復用SpringFramework接口WebApplicationInitializer,實現了相關的邏輯,那麽會出現問題。

所以SpringBoot單獨定義了一個ServletContextInitializer類。詳細可以看官方文檔。

SpringBoot使用的AnnotationConfigServletWebServerApplicationContext的容器,它父類ServletWebServerApplicationContext的onRefresh方法提供了構建webServer細節,即從Spring的BeanFactory獲取所有的ServletContextInitializer類。

技術分享圖片

SpringSecurity使用SecurityFilterAutoConfiguration構建了DelegatingFilterProxyRegistrationBean實例。

技術分享圖片

而我們的DelegatingFilterProxyRegistrationBean剛好就是一個ServletContextInitializer的實現類。

技術分享圖片

DelegatingFilterProxyRegistrationBean執行onStartup()方法邏輯,會註冊Filter到ServletContext中,如下

技術分享圖片

上圖所示,留意上面的$1,所以Filter的實現類是一個DelegatingFilterProxy匿名繼承類

技術分享圖片

2.小結

  a).SpringBoot初始化SpringSecurity的@Configuration類,構建一個匿名類DelegatingFilterProxyRegistrationBean$1實例,這個匿名類繼承DelegatingFilterProxy

  b).匿名類DelegatingFilterProxyRegistrationBean$1實例(繼承DelegatingFilterProxy)包裹了springSecurityFilterChain實例。

  c).匿名類DelegatingFilterProxyRegistrationBean$1實例註冊Filter映射url(默認為/*)到ServletContext中。

3.springSecurityFilterChain加載

SpringSecurity通過類WebSecurityConfiguration定義了一個bean名為springSecurityFilterChain的實例,如下。

技術分享圖片

上圖顯示springSecurityFilterChain實質上是通過WebSecurity調用build方法完成構建的,下面是WebSecurity的performBuild詳情

技術分享圖片

所以,我們的springSecurityFilterChain實例實質上是FilterChainProxy類型,FilterChainProxy有兩類組成:

  a).ignoredRequests生成的DefaultSecurityFilterChain實例

  b).模板類SecurityBuilder(實質上就是HttpSecurity類)調用buid方法生成的實例。

技術分享圖片

上圖所示,HttpSecurity就是上面內容"前言"例子的configure參數HttpSecurity,所以我們通過WebSecurityConfigurerAdapter調用configure方法配置HttpSecurity結果會在這裏用上。

技術分享圖片

4.HttpSecurity構建

未完待續……

SpringSecurity源碼解讀