确认自定义过滤器(使用@Order和@Component)在Sping Boot 3中的Spring Security过滤器之后运行

r9f1avp5  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(137)

我正在使用Spring Security作为依赖项构建一个Sping Boot v3.1.1应用程序。

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.1'
    id 'io.spring.dependency-management' version '1.1.0'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
}

字符串
我已经创建了两个自定义过滤器,希望它们在Spring Security过滤器之后运行(在链中的最后一个):

@Order(1)
@Component
public class DeviceFilter extends OncePerRequestFilter {}

@Order(2)
@Component
public class MdcFilter extends OncePerRequestFilter {}


他们正在工作,但我不能确认订单是否正确。
我试过这个:

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .formLogin(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable) // Removes CsrfFilter
                .logout(AbstractHttpConfigurer::disable) // Removes LogoutFilter
                .rememberMe(AbstractHttpConfigurer::disable) // Removes RememberMeAuthenticationFilter
                .requestCache(RequestCacheConfigurer::disable) // Removes RequestCacheAwareFilter
                
                .cors(withDefaults()) // Adds CorsFilter

                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/public/**").permitAll()
                        .anyRequest().authenticated()
                )

                .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults()));

        return http.build();
    }

}


控制台中的结果:

Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextHolderFilter
  HeaderWriterFilter
  CorsFilter
  BearerTokenAuthenticationFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]


如果您注意到,我的两个自定义过滤器不存在,但它们以某种方式工作。
我认为Spring Security筛选器独立于自定义筛选器,并且这些筛选器不会添加到它们所管理的筛选器数组中。我不确定,我不是这方面的Maven。
此外,我已经尝试把日志内我的两个自定义过滤器,以检查顺序。他们很好。

09:05AM INFO DeviceFilter                     : {} DeviceFilter!!!!!!!
09:05AM INFO MdcFilter                        : {} MdcFilter!!!!!!!


但到目前为止,我不能保证它们在Spring Security过滤器之后运行。* 原因是我只希望在用户成功通过身份验证并通过所有Spring Security检查的情况下才运行它们。*
我尝试过的另一件事是在securityFilterChain()方法中添加过滤器,这意味着我的过滤器不再实现@Order@Component

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // .......
                // ......
                

                .addFilterAfter(new DeviceFilter(), AuthorizationFilter.class);
                .addFilterAfter(new MdcFilter(), DeviceFilter.class);

        return http.build();
    }

}


控制台中的结果:

Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextHolderFilter
  HeaderWriterFilter
  CorsFilter
  BearerTokenAuthenticationFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  AuthorizationFilter
  DeviceFilter // <=================
  MdcFilter // <=================
]

我更愿意坚持使用@Order和@Component方法,因为这对我来说更容易。

在其他线程中,他们讨论了如何设置顺序。

我的问题是如何确认我的订单(使用@Order和@Component)是正确的,并且它们在Spring Security过滤器之后运行?
提前感谢,并感谢任何推动这一点。

cdmah0mi

cdmah0mi1#

你的猜测是正确的。Spring安全(即FilterChainProxy)使用的过滤器内部有自己的过滤器链(即SecurityFilterChain),这些内部过滤器的顺序不会受到@Order的影响。@Order只对标准servlet Filter bean(包括FilterChainProxy)有影响。
通过分析源代码,ServletContextInitializerBeans负责对所有基于@Order的标准servlet Filter bean进行排序。然后,它会根据这个排序顺序将Filter逐个注册到servlet容器。
因此,您可以通过定义CommandLineRunner来间接确认Filter订单,CommandLineRunner将在应用程序启动时执行以打印订单。例如:

@Bean
public CommandLineRunner cmdLineRunner(ApplicationContext context) {
    return args -> {
        ServletContextInitializerBeans scib = new ServletContextInitializerBeans(context,
                FilterRegistrationBean.class, DelegatingFilterProxyRegistrationBean.class);
        System.out.println("----");
        scib.iterator().forEachRemaining(s -> {
            System.out.println(s);
        });
    };
}

字符串
它会打印出类似这样的内容:

characterEncodingFilter urls=[/*] order=-2147483648
formContentFilter urls=[/*] order=-9900
requestContextFilter urls=[/*] order=-105
springSecurityFilterChain urls=[/*] order=-100
deviceFilter urls=[/*] order=1
mdcFilter urls=[/*] order=2
filterRegistrationBean urls=[/*] order=2147483647
dispatcherServlet urls=[/]

相关问题