简体   繁体   中英

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 :

@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 :

@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

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. Therefore, I removed the manually addition of the filter in the configure() method. The result was that the filter wasnt called at all.

  2. Instead of implementing the filter interface, try to extend the OncePerRequestFilter class. Done that, but the filter still triggered twice.

  3. Tried also to remove the @Component annotation and add the filter manually. In addition I had to move the CookieProcessor bean to the Configuration class. 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; nested exception is java.lang.IllegalStateException: No ServletContext set

I am using spring-security version 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. (See this ).

The your code in the @Bean is too complex. Create and return a TomcatContextCustomizer to do the modification. Your code will lead to circulair references which will lead to initializing errors.

Add the following @Bean method to your @SpringBootApplication annotated class

@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. (Spring Boot automatically registers all detected Filter instances to the regular filter chain).

@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.

@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());
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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