簡體   English   中英

spring-boot 中的過濾順序

[英]Filter order in spring-boot

如何在 spring-boot 中指定過濾器的順序? 我需要在 Spring Security 過濾器之后插入我的 MDC 過濾器。 我幾乎嘗試了所有方法,但我的過濾器始終是第一位的。 這不起作用:

@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public UserInsertingMdcFilter userInsertingMdcFilter() {
    return new UserInsertingMdcFilter();
}

這也不起作用:

@Bean
public FilterRegistrationBean userInsertingMdcFilterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    UserInsertingMdcFilter userFilter = new UserInsertingMdcFilter();
    registrationBean.setFilter(userFilter);
    registrationBean.setOrder(Integer.MAX_VALUE);
    return registrationBean;
}

來自 Spring 的人再次提供幫助。 https://github.com/spring-projects/spring-boot/issues/1640https://jira.spring.io/browse/SEC-2730

Spring Security 不會在它創建的 Filter bean 上設置順序。 這意味着,當 Boot 為其創建 FilterRegistrationBean 時,它會獲得默認順序,即 LOWEST_PRECEDENCE。

如果您希望自己的過濾器遵循 Spring Security 的過濾器,您可以為 Spring Security 的過濾器創建自己的注冊並指定順序。

所以我的問題的答案是:

@Bean
public FilterRegistrationBean securityFilterChain(@Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
    registration.setOrder(Integer.MAX_VALUE - 1);
    registration.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
    return registration;
}

@Bean
public FilterRegistrationBean userInsertingMdcFilterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    UserInsertingMdcFilter userFilter = new UserInsertingMdcFilter();
    registrationBean.setFilter(userFilter);
    registrationBean.setOrder(Integer.MAX_VALUE);
    return registrationBean;
}

這在 Spring Boot 1.2 中得到了修復。 安全鏈現在默認為 order 0

也可以通過屬性設置:

security.filter-order=0 # Security filter chain order.

https://github.com/spring-projects/spring-boot/issues/1640

這是一個與 Spring Boot 2 / Spring Security 5 兼容的答案,它允許您將過濾器插入過濾器鏈中的任意位置。

我的用例是一個自定義日志記錄javax.servlet.Filter ,我想在任何 Spring Security 過濾器之前執行它; 但是,以下步驟應該允許您在現有 Spring 過濾器鏈中的任何位置放置過濾器:

步驟 1:找出現有設置中 Spring 過濾器的順序。

將您最喜歡的遠程調試器連接到您的應用程序,並在org.springframework.security.web.FilterChainProxydoFilter(ServletRequest request, ServletResponse response)方法中設置斷點。 從 Spring Security 5.1.6 開始,即第 311 行。在您的調試器中,通過檢查this.additionalFilters找出現有的過濾器。 在我的應用程序中,訂單類似於:

0: WebAsyncManagerIntegrationFilter
1: SecurityContextPersistenceFilter
2: HeaderWriterFilter
...

第 2 步:使用 Spring 的 WebSecurityConfigurerAdapter 和 HttpSecurity 在所需位置插入過濾器

您可能已經擁有一個WebSecurityConfigurerAdapter @Override configure(HttpSecurity http)方法的@Override configure(HttpSecurity http) HttpSecurity公開了addFilterBeforeaddFilterAfter方法,以允許您將過濾器相對於鏈中的現有類放置。 您的過濾器(實例)是這些方法的第一個參數,您想要在之前或之后插入的過濾器的類是第二個參數。

就我而言,我希望我的自定義日志過濾器成為鏈中的第一個(我的代碼片段是 Kotlin,我將 Java 實現留給您):

override fun configure(http: HttpSecurity) {
    http
        .addFilterBefore(MyCustomLoggingFilter(), WebAsyncManagerIntegrationFilter::class.java)
        .authorizeRequests()
        .antMatchers(
        ...
        )
}

第 3 步:獲利!

使用上面步驟 1 中描述的調試方法來驗證您的過濾器是否位於過濾器鏈中的預期位置。

希望這可以幫助其他人。

請注意,Spring Security 過濾器鏈並不是過濾器的全部。 事實上,有一個完整的(非安全)過濾器鏈在起作用,其中一個過濾器是DelegatingFilterProxy一個實例,它(nomen est omen)委托給另一個名為FilterChainProxy的過濾器,它管理自己的過濾器子列表,所有這些過濾器都面向安全相關的話題。 這種模式的優點是所有安全過濾器都在一個地方並且相互正確排序。 但是,如果您需要所有安全過濾器之前之后執行過濾器,這根本無濟於事。 雖然您可以通過選擇該列表中的第一個或最后一個過濾器來使用HttpSecurity對象進行配置,但這在邏輯上很奇怪,因為您的過濾器很可能與安全無關。 如果您在DelegatingFilterProxy::doFilter(ServletRequest, ServletResponse, FilterChain)設置斷點,您將看到應用程序的整個過濾器鏈。 如果需要,您甚至可以深入到FilterChainProxy中查找所有 spring 安全過濾器。 然后就可以一一打開相關的類,找出它們配置的命令。 一旦您知道您的過濾器應該在哪里,您就可以對其進行注釋。

例如,如果您需要配置日志過濾器並且您想要記錄所有安全故障(需要在FilterChainProxy之前進行)但還想要一個有用的跟蹤 ID(需要在LazyTracingFilter之后LazyTracingFilter ,它具有配置的默認順序TraceHttpAutoConfiguration.TRACING_FILTER_ORDER = Ordered.HIGHEST_PRECEDENCE + 5 ) 你可以用@Order(Ordered.HIGHEST_PRECEDENCE + 6)注釋你的過濾器。

在你的第一種情況下,這是一個錯誤配置,spring 的文檔有特別提醒:

您不能通過使用 @Order 注釋其 bean 方法來配置過濾器的順序。

你可以從這里找到: https : //docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-embedded-container-servlets-filters-listeners -豆子

添加

logging.level.web=調試

application.properties 中,您可以看到已注冊過濾器的詳細信息,包括 springboot 啟動時它們的順序和 URL 模式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM