4

I'm trying to insert (at first position) a simple custom Cors filter inside the spring filter chain.

If I do it like this

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

it works perfectly I can verify it by putting a breakpoint in Spring's ServletHandler.java where there the line

chain=getFilterChain(baseRequest, target, servlet_holder);

I was just wondering if I wish not to use @Componenent and @Order and instead defining the Filter bean the Application context. How can I set the order of the filters ?

Johny19
  • 5,364
  • 14
  • 61
  • 99

3 Answers3

6

See example: In your class ServletInitializer:

@Bean
 public FilterRegistrationBean requestLogFilter() {
        final FilterRegistrationBean reg = new FilterRegistrationBean(createRequestLogFilter());
        reg.addUrlPatterns("/*");
        reg.setOrder(1); //defines filter execution order
        return reg;
 }

 @Bean
 public RequestLogFilter createRequestLogFilter(){
        return new RequestLogFilter();
 }

the name of my filter is "requestLogFilter"

Warning: Don't use @Component annotation at the class Filter.

4

In case of corsFilter, it is normally required to set the order of this filter to be loaded before springSecurityFilterChain and other filters such as errorPageFilter from spring boot to be laded at the very beginning of the chain. Otherwise CORS support will be broken and the required headers won't be introduced. This can be accomplished in following matter:

@Configuration
public class MyConfiguration {

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://domain1.com");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(Integer.MIN_VALUE);
        return bean;
    }
}

The bean.setOrder(Integer.MIN_VALUE) will make sure that is is the very first filter loaded. Even if there is other filters such as errorPage filter with order set to Integer.MIN_VALUE(-2147483648).

megalucio
  • 5,051
  • 2
  • 22
  • 26
  • Your solution works fine for me. However, I do not figure out why. I think this is a bug or drawback for CorsFilter. – chenatu Mar 13 '17 at 03:18
  • I would't think this is a bug, I'm sure it will work just fine without setting the order in the case where this will be the only one filter being used. However in the case where you are using other filters such as with spring security, you need to set up the right order in order of the chain in order. – megalucio Mar 13 '17 at 15:32
  • @megalucio I am getting exception while I am doing exactly same as you did. EXCEPTION Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'corsFilter' is expected to be of type 'org.springframework.web.filter.CorsFilter' but was actually of type 'org.springframework.boot.web.servlet.FilterRegistrationBean' – Mubasher Jan 10 '19 at 13:57
  • 1
    just changing corsFilter() to corsFilterBean() worked for me. – Mubasher Jan 10 '19 at 14:02
2

Another alternative is to have your filter implement org.springframework.core.Ordered, and this is the only option if you're using spring webflux (it doesn't have a FilterRegistrationBean):

public class CorsFilter implements Filter, Ordered {
    //...

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE
    }
}

or you can even make it a variable in your filter.

Vedavyas Bhat
  • 2,068
  • 1
  • 21
  • 31