2

I'm trying to add a CORS filter to my Spring web application but the filter is not being executed. I've followed the relevant steps here: https://spring.io/guides/gs/rest-service-cors/ to no avail. I'm not using Spring Boot. I'm bootstrapping my application using Spring's WebApplicationInitializer in a 3.0+ servlet spec container.

Everything else in my application is working: configuration classes, controllers, hibernate entities, etc.

Update 1:

The below answers worked for me by adding the filter to the servlet container:

container.addFilter("CorsFilter", CorsFilter.class)
          .addMappingForUrlPatterns(null, false, "/*");

However, I'm curious why Spring Boot does not require this? They must automatically search for Filters and add them to the context. Is there a straightforward way to do this? It seems unfortunate that I have to create a filter and then add it to some list in another class. It'd be nice if they were automatically registered like in Spring Boot.

Relevant code snippets:

WebApplicationInitializer:

public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext =
                new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext =
                new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(WebAppConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher =
                container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

}

AppConfig:

@Configuration
@ComponentScan
public class AppConfig {
}

WebAppConfig:

@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
@ComponentScan(basePackageClasses = AppConfig.class)
public class WebAppConfig extends WebMvcConfigurerAdapter {
}

CorsFilter:

@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
        httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String origin = httpRequest.getHeader("Origin");
        if (StringUtils.hasText(origin)) {

            boolean isMyDomain =
                Pattern.compile("^https://(.*?\\.)?mydomain.com(:\\d+)?$")
                        .matcher(origin)
                        .find();
            if (isMyDomain) {
                httpResponse.setHeader("Access-Control-Allow-Origin", origin);
            } else {
                httpResponse.setHeader("Access-Control-Allow-Origin", "mydomain");
            }

        }
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LoggerFactory.getLogger(getClass()).info("CorsFilter initiated");
    }

    @Override
    public void destroy() {
        LoggerFactory.getLogger(getClass()).info("CorsFilter destroyed");
    }
}
Corey
  • 1,133
  • 4
  • 17
  • 30
  • shouldn't you register your filter with the web container (e.g. by adding it to the web.xml) – Dev Blanked Feb 03 '15 at 07:54
  • possible duplicate of [How to write a custom filter in spring security?](http://stackoverflow.com/questions/11928637/how-to-write-a-custom-filter-in-spring-security) – User27854 Feb 03 '15 at 08:13

2 Answers2

1

You could add like this:

container.addFilter("CorsFilter", CorsFilter.class)
          .addMappingForUrlPatterns(null, false, "/*");
sven.kwiotek
  • 1,459
  • 15
  • 22
  • I've updated my question regarding Spring Boot's method of automatically registering servlet filters. – Corey Feb 03 '15 at 20:46
1

You have to just register your Filter in your AppInitializer.

public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext =
                new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext =
                new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(WebAppConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher =
                container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");

        //Added filter dynamically
        javax.servlet.FilterRegistration.Dynamic corsFilter = container.addFilter("corsfilter", CORSFilter.class);
        corsFilter.addMappingForUrlPatterns(null, true, "/*");
    }

}

You can take reference of this github repository.

Sheel
  • 1,010
  • 1
  • 17
  • 30
  • Ok great thanks I'll give it a shot... Out of curiosity, how does Spring Boot manage to do this without explicitly adding filters in their WebApplicationInitializer? With Spring Boot I can just add a javax.servlet.Filter as a spring bean and it does the rest. – Corey Feb 03 '15 at 18:27
  • Under 26.3.1 Servlets and Filters in Docs of http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html there it stand: "When using an embedded servlet container you can register Servlets and Filters directly as Spring beans. " – sven.kwiotek Feb 04 '15 at 07:44