Spring Rest and Kors

I am developing a Spring boot application with a Rest interface and popping darts.

XMLHttpRequest executes an OPTIONS request, which is processed completely correctly. After that, the final GET request is issued ("/ products") and does not execute:

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

After some debugging, I found the following: The AbstractHandlerMapping.corsConfiguration function is populated for all subclasses except the RestHandlerMapping repository. In RepositoryRestHandlerMapping no corsConfiguration is present / set at creation time and therefore will not be recognized as a cors path / resource.
=> No CORS headers
Could this be a problem? How can i install 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 installing Cors for 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 

Headers of the original answer:

 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 

Used Versions: Spring Download 1.3.0.M2 Spring 4.2.0.RC2

What am I missing?

+45
java spring spring-data-rest spring-mvc cors
Jul 30 '15 at 13:20
source share
3 answers

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

But now that DATAREST-573 has been fixed, RepositoryRestConfiguration now provides getCorsRegistry() for global configuration and @CrossOrigin annotations on the repository are also recognized, so this is the recommended approach. See the https://stackoverflow.com/a/166908/ for more examples.

For people who 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 , but keep in mind that Spring Framework 4.2 also provides CorsFilter that use the same CORS processing logic as the @CrossOrigin and addCorsMappings(CorsRegistry registry) approaches. By passing an UrlBasedCorsConfigurationSource instance to the UrlBasedCorsConfigurationSource constructor, you can easily get something as powerful as Spring's internal global CORS support.

If you use 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; } } 
+78
Jul 31 '15 at 14:18
source share

Since the Ingalls train was implemented , CORS support in Spring is now data. There are two solutions:

  • @CrossOrigin with origins , methods and allowedHeaders over the @RepositoryRestResource interface.

     @CrossOrigin(...) @RepositoryRestResource public interface PageRepository extends CrudRepository<Page, Long> { ... } 
  • Global configuration with RepositoryRestConfiguration inside the @Configuration class. Marking repositories with @CrossOrigin not required.

     @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); } } 
+8
Feb 22 '17 at 23:03
source share

For some reason, the approach suggested in the accepted answer above did not work for me after upgrading from Spring Boot 1.5.2 to 1.5.6.

As also noted by @BigDong's comment, the exception I received was:

BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' made an exception; the nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: A bean named 'corsFilter' is expected to be of type 'org.springframework.web.filter.CorsFilter', but actually is of type 'org.springframework.boot .web.servlet.FilterRegistrationBean

So, here is what I found to get a “global” CORS configuration for all endpoints in our REST API, whether they are implemented using Spring Data Rest or Spring MVC, all endpoints being protected by Spring Security.

I was unable to connect the CorsFilter to the request pipeline on the right, so instead I configured SDR and MVC separately, however, using this configuration for my CorsRegistry through this helper:

 public static void applyFullCorsAllowedPolicy(CorsRegistry registry) { registry.addMapping("/**") // .allowedOrigins("*") // .allowedMethods("OPTIONS", "HEAD", "GET", "PUT", "POST", "DELETE", "PATCH") // .allowedHeaders("*") // .exposedHeaders("WWW-Authenticate") // .allowCredentials(true) .maxAge(TimeUnit.DAYS.toSeconds(1)); } 

And then for MVC:

 @Configuration @EnableWebSecurity(debug = true) @EnableGlobalMethodSecurity(prePostEnabled = true) public class CustomWebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // enables CORS as per // https://docs.spring.io/spring-security/site/docs/current/reference/html/cors.html#cors http.cors() .and() // ... } @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { applyFullCorsAllowedPolicy(registry); } }; } } 

And then for the SDR:

 public class CustomRepositoryRestMvcConfiguration extends RepositoryRestConfigurerAdapter { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.setReturnBodyOnCreate(true); config.setReturnBodyForPutAndPost(true); config.setReturnBodyOnUpdate(true); config.setMaxPageSize(250); config.setDefaultPageSize(50); config.setDefaultMediaType(MediaTypes.HAL_JSON); config.useHalAsDefaultJsonMediaType(true); CustomWebSecurityConfiguration.applyFullCorsAllowedPolicy(config.getCorsRegistry()); } 

Here is another link to this topic that helped me come up with this answer:

+4
Aug 27 '17 at 12:59 on
source share



All Articles