spring-security源碼閱讀-總結(二十六)

spring-security很重?

身邊一提到spring-security,都覺得很重,寧願自己寫個filter快速實現認證,確實如此嗎,spring-security本質也是基於servlet-filter作爲切入點。作爲框架,把正常驗證流程差異化的地方都封裝抽象出來了。

我們只需要根據他的每個差異化的地方完成我們自己的配置就行了。但是學習成本會高一點。

spring-security的配置是如何實現的?

HttpSecurity內部存儲了一個List config接口 比如

    public CorsConfigurer<HttpSecurity> cors() throws Exception {
        return getOrApply(new CorsConfigurer<>());
    }

getOrApply會找結合裏面有沒有定義過這個元素,如果沒定義則new一個並添加,定義了則返回集合裏面存在的。

然後我們基於CorsConfigurer就可以自己這個過濾器的自定義配置了。當調用and 就返回HttpSecurity當前對象,繼續.其他配置設置。最後HttpSecurity的build方法會遍歷這些config的config方法,生成Filter

spring security每個filter都有自己的抽象,所以每個config都有自己的.配置

   @Bean
    protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        // 登出
        httpSecurity
                // 開啓跨域
                .cors().and()
                // CSRF 禁用,因爲不使用 Session
                .csrf().disable()
                // 基於 token 機制,所以不需要 Session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .headers().frameOptions().disable().and()
                // 一堆自定義的 Spring Security 處理器
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);
   
        // 獲得 @PermitAll 帶來的 URL 列表,免登錄
        Multimap<HttpMethod, String> permitAllUrls = getPermitAllUrlsFromAnnotations();
        // 設置每個請求的權限
        httpSecurity
                // ①:全局共享規則
                //
                .authorizeRequests()
                // 1.1 靜態資源,可匿名訪問
                .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                // 1.2 設置 @PermitAll 無需認證
                //FilterSecurityInterceptor 攔截處理 封裝spel,root對象爲SecurityExpressionOperations對象 交給el執行permitAll表達式就是調用方法
                .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
                // 1.3 基於 yudao.security.permit-all-urls 無需認證
                .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
                // 1.4 設置 App API 無需認證
                .antMatchers(buildAppApi("/**")).permitAll()
                // ②:每個項目的自定義規則
                .and().authorizeRequests(registry -> // 下面,循環設置自定義規則
                        authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
                // ③:兜底規則,必須認證
                .authorizeRequests()
                .anyRequest().authenticated()
        ;

        // 添加 Token Filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        return httpSecurity.build();
    }

WebSecurity和HttpSecurty的關係?

WebSecurity就是WebSecurityConfigurerAdapter的父類,HttpSecurty由WebSecurity構建。我們重寫WebSecurityConfigurerAdapter的configure可以拿到HttpSecurty,就可以手動添加filter或者基於現有的filter做一些定製化配置

spring-security如何實現身份認證的?

 1.首先根據我們的配置看走哪個filter鏈,httpsecurity是支持配置針對哪些url生效的比如(默認**/**),一個httpSecurity代表一個鏈路,

 httpSecurity.antMatcher("/product/*")
                // 開啓跨域
                .cors().and()
                // CSRF 禁用,因爲不使用 Session
                .csrf().disable()
                // 基於 token 機制,所以不需要 Session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .headers().frameOptions().disable().and()
                // 一堆自定義的 Spring Security 處理器
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);

2.然後是我們配置的哪些接口無需認證,走ExpressionUrlAuthorizationConfigurer的構建filter。

   httpSecurity
                // ①:全局共享規則
                //
                .authorizeRequests()
                // 1.1 靜態資源,可匿名訪問
                .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                // 1.2 設置 @PermitAll 無需認證
                //FilterSecurityInterceptor 攔截處理 封裝spel,root對象爲SecurityExpressionOperations對象 交給el執行permitAll表達式就是調用方法
                .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
                // 1.3 基於 yudao.security.permit-all-urls 無需認證
                .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
                // 1.4 設置 App API 無需認證
                .antMatchers(buildAppApi("/**")).permitAll()
                // ②:每個項目的自定義規則
                .and().authorizeRequests(registry -> // 下面,循環設置自定義規則
                        authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
                // ③:兜底規則,必須認證
                .authorizeRequests()
                .anyRequest().authenticated()
        ;

支持多個配置,其實後面對應的filter是完成url匹配調用一個實體的方法

3.然後走我們後續的認證filter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章