欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Security?過(guò)濾器注冊(cè)脈絡(luò)梳理

 更新時(shí)間:2022年08月11日 14:27:16   作者:青陽(yáng)半雪  
這篇文章主要介紹了Spring?Security過(guò)濾器注冊(cè)脈絡(luò)梳理,Spring?Security在Servlet的過(guò)濾鏈中注冊(cè)了一個(gè)過(guò)濾器FilterChainProxy,它會(huì)把請(qǐng)求代理到Spring?Security自己維護(hù)的多個(gè)過(guò)濾鏈,每個(gè)過(guò)濾鏈會(huì)匹配一些URL,如果匹配則執(zhí)行對(duì)應(yīng)的過(guò)濾器

1 簡(jiǎn)述

Spring Security 本質(zhì)上就是通過(guò)一系列的過(guò)濾器,進(jìn)行業(yè)務(wù)的處理。

Spring Security 在 Servlet 的過(guò)濾鏈(filter chain)中注冊(cè)了一個(gè)過(guò)濾器 FilterChainProxy,它會(huì)把請(qǐng)求代理到 Spring Security 自己維護(hù)的多個(gè)過(guò)濾鏈,每個(gè)過(guò)濾鏈會(huì)匹配一些 URL,如果匹配則執(zhí)行對(duì)應(yīng)的過(guò)濾器。過(guò)濾鏈?zhǔn)怯许樞虻?,一個(gè)請(qǐng)求只會(huì)執(zhí)行第一條匹配的過(guò)濾鏈。Spring Security 的配置本質(zhì)上就是新增、刪除、修改過(guò)濾器

但是萬(wàn)物終歸有源頭,過(guò)濾器是如何注冊(cè)進(jìn)來(lái)的,通過(guò)過(guò)程了解注冊(cè)的骨架。

注明 這里只是使用了 spring web + spring security,同時(shí)使用 web.xml 的風(fēng)格進(jìn)行配置,如果你使用 SPI 機(jī)制(沒(méi)有使用 web.xml),殊途同歸。

2 注冊(cè)過(guò)程

2.1 web.xml 配置

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

其中 DelegatingFilterProxy 類圖如下:

根據(jù)類圖看出,DelegatingFilterProxy 繼承 GenericFilterBean,其間接實(shí)現(xiàn)了 Filter 接口,所以從類型上看,其也是一個(gè)過(guò)濾器。

 從 Spring 容器中尋找 targetBeanName=springSecurityFilterChain 的 Bean, 從 DelegatingFilterProxy 的名字上看,知道它其實(shí)是一個(gè)代理類,真正執(zhí)行業(yè)務(wù)的,是 filter-name 指定的 springSecurityFilterChain 這個(gè) bean。接下來(lái),問(wèn)題來(lái)了,springSecurityFilterChain 這個(gè) bean 又是在什么時(shí)候注冊(cè)的呢

2.2 EnableWebSecurity 注解

我們一般在使用 Spring Security 的時(shí)候,都會(huì)自定義繼承 WebSecurityConfigurerAdapter,同時(shí)結(jié)合使用 EnableWebSecurity 注解,然后在自定義的類中進(jìn)行各種各樣滿足業(yè)務(wù)的工作。

@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    ...
}

這里我們重點(diǎn)關(guān)注的是 EnableWebSecurity 注解,查看下其源碼,做了兩個(gè)非常重要的點(diǎn)

  • 1 導(dǎo)入 WebSecurityConfiguration 配置。
  • 2 通過(guò) @EnableGlobalAuthentication 注解引入全局配置
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ 
    WebSecurityConfiguration.class,
    SpringWebMvcImportSelector.class,
    OAuth2ImportSelector.class,
    HttpSecurityConfiguration.class
})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {

   /**
    * Controls debugging support for Spring Security. Default is false.
    * @return if true, enables debug support with Spring Security
    */
   boolean debug() default false;

}

此注解中由使用了 Import 注解引入了其他的 bean,然后查看其源碼,重點(diǎn)關(guān)注 WebSecurityConfiguration。

2.3 WebSecurityConfiguration 類

這個(gè)類里面比較重要的就兩個(gè)方法:

1 springSecurityFilterChain

springSecurityFilterChain 方法上添加了 @Bean注解,可以知道是創(chuàng)建了springSecurityFilterChain bean

2 setFilterChainProxySecurityConfigurer

這個(gè)方式設(shè)置了對(duì)應(yīng)的配置,注意,這個(gè)方法優(yōu)先上面的方法執(zhí)行。

分析其重點(diǎn)代碼

private WebSecurity webSecurity;

// 注入 bean
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
   boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
   boolean hasFilterChain = !this.securityFilterChains.isEmpty();
   ...
   if (!hasConfigurers && !hasFilterChain) {
      WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
            .postProcess(new WebSecurityConfigurerAdapter() {
            });
      this.webSecurity.apply(adapter);
   }
   for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
      this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
      for (Filter filter : securityFilterChain.getFilters()) {
         if (filter instanceof FilterSecurityInterceptor) {
            this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
            break;
         }
      }
   }
   for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
      customizer.customize(this.webSecurity);
   }

   // 重點(diǎn)關(guān)注
   return this.webSecurity.build();
}
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
      @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
      throws Exception {
   this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
   if (this.debugEnabled != null) {
      this.webSecurity.debug(this.debugEnabled);
   }
   webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
   Integer previousOrder = null;
   Object previousConfig = null;
   for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
      Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
      if (previousOrder != null && previousOrder.equals(order)) {
         throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order
               + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
      }
      previousOrder = order;
      previousConfig = config;
   }
   for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
      this.webSecurity.apply(webSecurityConfigurer);
   }
   this.webSecurityConfigurers = webSecurityConfigurers;
}

我們先看執(zhí)行的 setFilterChainProxySecurityConfigurer 方法,其中參數(shù) webSecurityConfigurers 是一個(gè) List,它實(shí)際上是所有 WebSecurityConfigurerAdapter 的子類,那如果我們定義了自定義的配置類,也意味著讀取了我們自定義的類。

接著看到 springSecurityFilterChain 方法注冊(cè)了一個(gè)名字為 AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME 的 bean,翻看源碼,其實(shí)名字就是在 web.xml 中配置的 filter-name,即 springSecurityFilterChain,到這里困惑解開了一部分,原來(lái)查詢的 bean 是在這里注入的。同時(shí)也要求了在使用 spring-security 時(shí),在 web.xml 中配置 filter 時(shí),不能是其他名字。

根據(jù) this.webSecurity.build 這行代碼,發(fā)現(xiàn)真正構(gòu)建過(guò)濾器的是 WebSecurity 類

2.4 WebSecurity 類

接上一步中的代碼

   // 重點(diǎn)關(guān)注
   return this.webSecurity.build();

知道起作用的是 WebSecurity 類,其類圖結(jié)構(gòu)如下:

根據(jù)源碼,定位到 WebSecurity 類中的 performBuild 方法

@Override
protected Filter performBuild() throws Exception {
   ...
   int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
   List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
   for (RequestMatcher ignoredRequest : this.ignoredRequests) {
      securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
   }

   // ① 調(diào)用 securityFilterChainBuilder 的 build() 方法
   for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
      securityFilterChains.add(securityFilterChainBuilder.build());
   }
   FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
   if (this.httpFirewall != null) {
      filterChainProxy.setFirewall(this.httpFirewall);
   }
   if (this.requestRejectedHandler != null) {
      filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
   }
   filterChainProxy.afterPropertiesSet();

   Filter result = filterChainProxy;
   ...
   this.postBuildAction.run();
   return result;
}

代碼分析:

  • 1 代碼中的  處,重點(diǎn)關(guān)注,通過(guò)斷點(diǎn)調(diào)試,發(fā)現(xiàn)其實(shí)這里的 securityFilterChainBuilder 就是 HttpSecurity,到這里也很清楚了,默認(rèn)以及自定義過(guò)濾器是通過(guò) HttpSecurity 加載進(jìn)來(lái)的。
  • 2 創(chuàng)建好過(guò)濾器鏈之后,然后實(shí)例化 filterChainProxy 進(jìn)行返回

根據(jù)源碼知道 performBuild 方法最終返回的其實(shí)是一個(gè) filterChainProxy 實(shí)例,接下來(lái)我們?cè)訇P(guān)注下 filterChainProxy 類。

2.5 FilterChainProxy 類

其類圖結(jié)構(gòu)如下

查看其關(guān)鍵代碼:

public class FilterChainProxy extends GenericFilterBean {

   // 維護(hù)的 spring security 過(guò)濾器鏈列表
   private List<SecurityFilterChain> filterChains;
   public FilterChainProxy(SecurityFilterChain chain) {
      this(Arrays.asList(chain));
   }
   public FilterChainProxy(List<SecurityFilterChain> filterChains) {
      this.filterChains = filterChains;
   }
    @Override
    public void doFilter(
        ServletRequest request,
        ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
            boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
            if (!clearContext) {
                    doFilterInternal(request, response, chain);
                    return;
            }
            try {
                    request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

                    // 真正起作用的函數(shù)
                    doFilterInternal(request, response, chain);
            }
            catch (RequestRejectedException ex) {
                    this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);
            }
    ...
    }
    private void doFilterInternal(
        ServletRequest request,
        ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
            FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest(
                (HttpServletRequest) request);
            HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse(
                (HttpServletResponse) response);
            List<Filter> filters = getFilters(firewallRequest);
            if (filters == null || filters.size() == 0) {
                    ...
                    chain.doFilter(firewallRequest, firewallResponse);
                    return;
            }
            VirtualFilterChain virtualFilterChain = new VirtualFilterChain(
                firewallRequest, chain, filters);
            virtualFilterChain.doFilter(firewallRequest, firewallResponse);
    }
}

通過(guò)代碼分析,FilterChainProxy 這個(gè)類維護(hù)了真正的過(guò)濾器鏈列表,即 SecurityFilterChain 類型的過(guò)濾器鏈,注意,SecurityFilterChain 是過(guò)濾器鏈,而不是一個(gè)個(gè)的過(guò)濾器,過(guò)濾器會(huì)有其他的操作塞到過(guò)濾器鏈中,即 2.4 中的代碼塊,代碼如下。

   for (RequestMatcher ignoredRequest : this.ignoredRequests) {
      securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
   }
   // ① 調(diào)用 securityFilterChainBuilder 的 build() 方法
   for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
      securityFilterChains.add(securityFilterChainBuilder.build());
   }

這段代碼其實(shí)執(zhí)行的業(yè)務(wù)就是把過(guò)濾器塞入到過(guò)濾器鏈中。

這里也更加清楚了, Spring Security Filter 并不是直接嵌入到 Web Filter 中的,而是通過(guò) FilterChainProxy 來(lái)統(tǒng)一管理 Spring Security Filter,FilterChainProxy 本身則通過(guò) Spring 提供的 DelegatingFilterProxy 代理過(guò)濾器嵌入到 Web Filter 之中。

3 小結(jié)

根據(jù)趟源碼,大概了解了過(guò)濾器注冊(cè)的流程:

  • web.xml 中 DelegatingFilterProxy 配置
  • EnableWebSecurity 注解引入配置初始化
  • WebSecurityConfiguration 類注入 springSecurityFilterChain 的 bean 并開始構(gòu)建過(guò)濾器
  • WebSecurity 類中的 performBuild 方法把過(guò)濾器都處理好,放到過(guò)濾器鏈中,接著實(shí)例化 filterChainProxy,這里實(shí)例化返回的對(duì)象就是第三步的過(guò)濾器

到此這篇關(guān)于Spring Security 過(guò)濾器注冊(cè)脈絡(luò)梳理的文章就介紹到這了,更多相關(guān)Spring Security 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java線程變量ThreadLocal詳細(xì)解讀

    Java線程變量ThreadLocal詳細(xì)解讀

    這篇文章主要介紹了Java線程變量ThreadLocal詳細(xì)解讀,多線程訪問(wèn)同一個(gè)變量的時(shí)候,很容易出現(xiàn)問(wèn)題,特別是多線程對(duì)一個(gè)共享變量進(jìn)行寫入的時(shí)候,為了線程的安全在進(jìn)行數(shù)據(jù)寫入時(shí)候會(huì)進(jìn)行數(shù)據(jù)的同步,需要的朋友可以參考下
    2024-01-01
  • Java中關(guān)于內(nèi)存泄漏出現(xiàn)的原因匯總及如何避免內(nèi)存泄漏(超詳細(xì)版)

    Java中關(guān)于內(nèi)存泄漏出現(xiàn)的原因匯總及如何避免內(nèi)存泄漏(超詳細(xì)版)

    這篇文章主要介紹了Java中關(guān)于內(nèi)存泄漏出現(xiàn)的原因匯總及如何避免內(nèi)存泄漏(超詳細(xì)版)的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之詳解易寶支付的流程

    SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之詳解易寶支付的流程

    這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之易寶支付的流程,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java  Object類中的常用API介紹

    Java  Object類中的常用API介紹

    這篇文章主要介紹了Java  Object類中的常用API介紹,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • 查看import的類是出自哪個(gè)jar包的方法

    查看import的類是出自哪個(gè)jar包的方法

    下面小編就為大家?guī)?lái)一篇查看import的類是出自哪個(gè)jar包的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • SpringBoot異常處理之異常顯示的頁(yè)面問(wèn)題

    SpringBoot異常處理之異常顯示的頁(yè)面問(wèn)題

    這篇文章主要介紹了SpringBoot異常處理異常顯示的頁(yè)面的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • MyBatis-Plus 自定義sql語(yǔ)句的實(shí)現(xiàn)

    MyBatis-Plus 自定義sql語(yǔ)句的實(shí)現(xiàn)

    這篇文章主要介紹了MyBatis-Plus 自定義sql語(yǔ)句的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 如何使用JFrame完成動(dòng)態(tài)模擬時(shí)鐘

    如何使用JFrame完成動(dòng)態(tài)模擬時(shí)鐘

    本文介紹了如何使用JFrame完成動(dòng)態(tài)模擬時(shí)鐘,需要的朋友可以參考下
    2015-08-08
  • Java享元設(shè)計(jì)模式優(yōu)化對(duì)象創(chuàng)建提高性能和效率

    Java享元設(shè)計(jì)模式優(yōu)化對(duì)象創(chuàng)建提高性能和效率

    Java享元設(shè)計(jì)模式通過(guò)共享可重用的對(duì)象,減少了系統(tǒng)中對(duì)象的數(shù)量,優(yōu)化了對(duì)象的創(chuàng)建和管理,提高了性能和效率。它是一種經(jīng)典的設(shè)計(jì)模式,適用于需要處理大量相似對(duì)象的應(yīng)用程序
    2023-04-04
  • Java?Bean轉(zhuǎn)Map的那些踩坑實(shí)戰(zhàn)

    Java?Bean轉(zhuǎn)Map的那些踩坑實(shí)戰(zhàn)

    項(xiàng)目中有時(shí)會(huì)遇到Map轉(zhuǎn)Bean,Bean轉(zhuǎn)Map的情況,下面這篇文章主要給大家介紹了關(guān)于Java?Bean轉(zhuǎn)Map那些踩坑的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07

最新評(píng)論