Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Rest and Cors

I am developing a Spring Boot application with a Rest interface and a dart fronted.

The XMLHttpRequest does execute a OPTIONS request which is handled totally correct. After this, the final GET ("/products") request is issued and fails:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63343' is therefore not allowed access.

After some debugging I have found the following: The AbstractHandlerMapping.corsConfiguration is populated for all Subclasses except RepositoryRestHandlerMapping. In the RepositoryRestHandlerMapping no corsConfiguration is present / set at creation time and so it won't get recognized as cors path / resource.
=> No CORS headers attached
Could that be the problem? How can I set it?

Configuration classes:

@Configuration
public class RestConfiguration extends RepositoryRestMvcConfiguration {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowCredentials(false).allowedOrigins("*").allowedMethods("PUT", "POST", "GET", "OPTIONS", "DELETE").exposedHeaders("Authorization", "Content-Type");
    }

   ...
}

I even tried to set the Cors per annotation:

@CrossOrigin( methods = RequestMethod.GET, allowCredentials = "false")
public interface ProductRepository extends CrudRepository<Product, String> {


}

Raw request headers:

GET /products HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
authorization: Basic dXNlcjpwYXNzd29yZA==
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/43.0.2357.130 Chrome/43.0.2357.130 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://localhost:63343/inventory-web/web/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

Raw response headers:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 30 Jul 2015 15:58:03 GMT

Versions used: Spring Boot 1.3.0.M2 Spring 4.2.0.RC2

What do I miss?

like image 538
Thomas Letsch Avatar asked Jul 30 '15 13:07

Thomas Letsch


People also ask

How do I enable CORS in Spring rest API?

Enable CORS in Controller Method We need to set the origins for RESTful web service by using @CrossOrigin annotation for the controller method. This @CrossOrigin annotation supports specific REST API, and not for the entire application.

Is CORS required for rest API?

Cross-origin resource sharing (CORS) is a browser security feature that restricts cross-origin HTTP requests that are initiated from scripts running in the browser. If your REST API's resources receive non-simple cross-origin HTTP requests, you need to enable CORS support.

Is CORS enabled by default in Spring boot?

No. You need to add @CrossOrigin annotation by yourself to get CORS Support in Spring.


2 Answers

Indeed, before Spring Data REST 2.6 (Ingalls) only HandlerMapping instances created by Spring MVC WebMvcConfigurationSupport and controllers annotated with @CrossOrigin were CORS aware.

But now that DATAREST-573 has been fixed, RepositoryRestConfiguration now exposes a getCorsRegistry() for global setup and @CrossOrigin annotations on repositories are also recognized so this is the recommended approach. See https://stackoverflow.com/a/42403956/1092077 answer for concrete examples.

For people that have to stick to Spring Data REST 2.5 (Hopper) or previous versions, I think the best solution is to use a filter based approach. You could obviously use Tomcat, Jetty or this one, but be aware that Spring Framework 4.2 also provides a CorsFilter that use the same CORS processing logic that @CrossOrigin and addCorsMappings(CorsRegistry registry) approaches. By passing an UrlBasedCorsConfigurationSource instance to the CorsFilter constructor parameter, you could easily get something as powerful as Spring native CORS global support.

If you are using Spring Boot (which supports Filter beans), it could be something like:

@Configuration public class RestConfiguration {      @Bean     public FilterRegistrationBean corsFilter() {         UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();         CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();         source.registerCorsConfiguration("/**", config);         FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));         bean.setOrder(0);         return bean;     } } 
like image 116
Sébastien Deleuze Avatar answered Sep 22 '22 15:09

Sébastien Deleuze


Since the Ingalls train has been realised, the support of CORS in Spring Data is now on. There are two ways to deal with:

  1. The @CrossOrigin annotation with specifying origins, methods, and allowedHeaders over a @RepositoryRestResource interface.

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long> { ... }
    
  2. A global configuration with the RepositoryRestConfiguration inside a @Configuration class. Marking repositories by the @CrossOrigin is not necessary then.

    @Configuration
    public class GlobalRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
    
        @Override
        public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
            config.getCorsRegistry()
                      .addMapping(CORS_BASE_PATTERN)
                      .allowedOrigins(ALLOWED_ORIGINS)
                      .allowedHeaders(ALLOWED_HEADERS)
                      .allowedMethods(ALLOWED_METHODS);
         }
    
    }
    
like image 34
Andrew Tobilko Avatar answered Sep 20 '22 15:09

Andrew Tobilko