简体   繁体   English

Spring Boot 过滤器被调用两次或根本不调用

[英]Spring boot filter called twice or not called at all

I implemented a customFilter that adds something from the request`s cookies to its headers :我实现了一个 customFilter,它将请求的 cookie 中的内容添加到其标头中:

@Component
@Slf4j
public class MyCustomFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
        .... some logic...
        log.info("Sending request to next chain for validation..");
        chain.doFilter(request, response);
        log.info("Authentication completed sucessfully");
    }

    @Bean
    // This method is needed to replace the default cookieFilter.json processor of tomcat that ignores the jwt cookieFilter.json
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
        return tomcatServletWebServerFactory -> tomcatServletWebServerFactory.addContextCustomizers((TomcatContextCustomizer) context -> {
            context.setCookieProcessor(new LegacyCookieProcessor());
        });
    }

}

My WebSecurityConfigurerAdapter class :我的 WebSecurityConfigurerAdapter 类:

@Configuration
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //configuring strategy
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated().and()
                .oauth2ResourceServer().jwt().and();
        http.csrf().disable();
        http.addFilterBefore(new MyCustomFilter (), UsernamePasswordAuthenticationFilter.class);
        http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
    }

}

When I run the code and send a request via postman/curl I see that the filter triggered twice in the当我运行代码并通过 postman/curl 发送请求时,我看到过滤器在

Sending request to next chain for validation..
Sending request to next chain for validation..
Authentication completed sucessfully
Authentication completed sucessfully

I found a few posts about issue and I tried the following solutions :我找到了一些关于问题的帖子,并尝试了以下解决方案:

  1. It happens because spring registers the beans automatically and I add the filter manually in the configure method.发生这种情况是因为 spring 自动注册了 bean,而我在配置方法中手动添加了过滤器。 Therefore, I removed the manually addition of the filter in the configure() method.因此,我删除了在 configure() 方法中手动添加过滤器。 The result was that the filter wasnt called at all.结果是根本没有调用过滤器。

  2. Instead of implementing the filter interface, try to extend the OncePerRequestFilter class.尝试扩展OncePerRequestFilter类,而不是实现过滤器接口。 Done that, but the filter still triggered twice.这样做了,但过滤器仍然触发了两次。

  3. Tried also to remove the @Component annotation and add the filter manually.还尝试删除@Component注释并手动添加过滤器。 In addition I had to move the CookieProcessor bean to the Configuration class.此外,我必须将CookieProcessor bean 移至 Configuration 类。 The problem that raised afterwards is that the app fails to start because of the following error :之后出现的问题是应用程序无法启动,因为以下错误:

    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception;引起:org.springframework.beans.BeanInstantiationException:无法实例化[org.springframework.web.servlet.HandlerMapping]:工厂方法'resourceHandlerMapping'抛出异常; nested exception is java.lang.IllegalStateException: No ServletContext set嵌套异常是 java.lang.IllegalStateException: No ServletContext set

I am using spring-security version 5.3.3.我正在使用 spring-security 版本 5.3.3。

As a rule of thumb, don't add @Bean methods to @Component classes as those are handled differently than those in @Configuration classes.根据经验,不要将@Bean方法添加到@Component类,因为它们的处理方式与@Configuration类中的方法不同。 (See this ). (见这个)。

The your code in the @Bean is too complex. @Bean的代码太复杂了。 Create and return a TomcatContextCustomizer to do the modification.创建并返回一个TomcatContextCustomizer来进行修改。 Your code will lead to circulair references which will lead to initializing errors.您的代码将导致循环引用,这将导致初始化错误。

Add the following @Bean method to your @SpringBootApplication annotated class将以下@Bean方法添加到您的@SpringBootApplication注释类中

@Bean
public TomactContextCustomizer cookieProcessorCustomizer() {
  return (context) -> context.setCookieProcessor(new LegacyCookieProcessor());
}

Now in your Filter either remove the @Component or add an accompying FilterRegistrationBean to prevent it from being added to the regular chain of filters.现在在您的Filter中删除@Component添加一个伴随的FilterRegistrationBean以防止将其添加到常规过滤器链中。 (Spring Boot automatically registers all detected Filter instances to the regular filter chain). (Spring Boot 自动将所有检测到的Filter实例注册到常规过滤器链)。

@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistrationBean(MyFilter myFilter) {
  FilterRegistrationBean<MyFilter> frb = new FilterRegistrationBean<>(myFilter);
  frb.setEnabled(false);
  return frb;
}

If you remove @Component the above snippet isn't needed if you don't then you should reuse the scanned MyFilter instance in your security configuration.如果您删除@Component ,则不需要上述代码段,如果您不这样做,则应在安全配置中重用扫描的MyFilter实例。

@Configuration
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyFilter myFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //configuring strategy
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .anyRequest().authenticated().and()
                .oauth2ResourceServer().jwt().and();
        http.csrf().disable();
        http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
        http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM