Spring Data Rest和Cors

Tho*_*sch 53 java spring spring-mvc cors spring-data-rest

我正在开发一个带有Rest接口和dart前端的Spring Boot应用程序.

XMLHttpRequest确实执行一个完全正确处理的OPTIONS请求.在此之后,发出最终的GET("/ products")请求并失败:

请求的资源上不存在"Access-Control-Allow-Origin"标头.原产地" 的http://本地主机:63343 ",因此没有允许访问.

经过一些调试后,我发现了以下内容:为RepositoryRestHandlerMapping之外的所有子类填充了AbstractHandlerMapping.corsConfiguration.在RepositoryRestHandlerMapping中,没有corsConfiguration在创建时存在/设置,因此它不会被识别为cors路径/资源.
=>没有连接CORS标头
这可能是问题吗?我怎么设置它?

配置类:

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

   ...
}
Run Code Online (Sandbox Code Playgroud)

我甚至尝试设置每个注释的Cors:

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


}
Run Code Online (Sandbox Code Playgroud)

原始请求标头:

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
Run Code Online (Sandbox Code Playgroud)

原始响应标头:

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
Run Code Online (Sandbox Code Playgroud)

使用的版本:Spring Boot 1.3.0.M2 Spring 4.2.0.RC2

我错过了什么?

Séb*_*uze 97

实际上,在Spring Data REST 2.6(Ingalls)之前,只有HandlerMappingSpring MVC创建的实例WebMvcConfigurationSupport和带注释的控制器才能@CrossOrigin识别CORS.

但是现在已经修复了DATAREST-573,RepositoryRestConfiguration现在公开了一个getCorsRegistry()全局设置,并且@CrossOrigin还可以识别存储库上的注释,因此这是推荐的方法.有关具体示例,请参阅/sf/answers/2968276951/答案.

对于那些必须坚持使用Spring Data REST 2.5(Hopper)或以前版本的人,我认为最好的解决方案是使用基于过滤器的方法.显然你可以使用Tomcat,Jetty或者这个,但要注意Spring Framework 4.2还提供了一个CorsFilter使用相同@CrossOriginaddCorsMappings(CorsRegistry registry)接近的CORS处理逻辑的方法.通过将UrlBasedCorsConfigurationSource实例传递给CorsFilter构造函数参数,您可以轻松获得与Spring本机CORS全局支持一样强大的功能.

如果您使用的是Spring Boot(支持Filterbean),它可能是这样的:

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • BeanInstantiationException:无法实例化[javax.servlet.Filter]:工厂方法'springSecurityFilterChain'抛出异常; 嵌套异常是org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为'corsFilter'的bean应该是'org.springframework.web.filter.CorsFilter'类型,但实际上是'org.springframework.boot.web.servlet'类型.FilterRegistrationBean (10认同)
  • 为了使用Spring-Security,我不得不使用第一个解决方案并将`CorsFilter`添加到Spring-Security过滤器链中,如下所示:`http.addFilterBefore(corsFilter,ChannelProcessingFilter.class)` (5认同)
  • 我已经用'FilterRegistrationBean更新我的[春季+ CORS的博客文章(https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#filter-based-cors-support) `.请注意,支持`config.addAllowedMethod("*")`. (4认同)
  • 出于某种原因,`new CorsFilter(source)`会抛出一个运行时异常,所以我最终手工创建了一个SimpleCorsFilter.但这个答案确实让我知道,当一切看起来都正确连接时,我并不疯狂. (3认同)

And*_*lko 20

自从Ingalls列车实现以来,现在开始在Spring Data中支持CORS.有两种方法可以解决:

  1. @CrossOrigin带有指定origins,methodsallowedHeaders通过@RepositoryRestResource接口的注释.

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long> { ... }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 具有RepositoryRestConfiguration内部@Configuration类的全局配置.@CrossOrigin因此不需要标记存储库.

    @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);
         }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)


Joh*_*lph 8

出于某种原因,从Spring Boot 1.5.2升级到1.5.6后,上面接受的答案中建议的方法对我不起作用.

正如@BigDong的评论所指出的那样,我得到的例外是:

BeanInstantiationException:无法实例化[javax.servlet.Filter]:工厂方法'springSecurityFilterChain'抛出异常; 嵌套异常是org.springframework.beans.factory.BeanNotOfRequiredTypeExcep tion:名为'corsFilter'的bean应该是'org.springframework.web.filter.CorsFilter'类型,但实际上是'org.springframework.boot.web'类型.servlet.FilterRegistrationBean

所以我在这里得到的是为REST API中的所有端点获取"全局"CORS配置,无论它们是使用Spring Data Rest还是Spring MVC实现的,所有端点都受Spring Security保护.

我无法CorsFilter在正确的位置挂钩到请求管道,所以我分别配置了SDR和MVC,但是使用相同的配置来CorsRegistry通过这个帮助器:

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));
}
Run Code Online (Sandbox Code Playgroud)

然后对于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);
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

然后是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());
}
Run Code Online (Sandbox Code Playgroud)

这里有一些关于这个主题的进一步参考,帮助我得出了这个答案:


小智 8

RepositoryRestConfigurerAdapter从 3.1 开始被弃用,所以如果你使用 spring boot 和 data-rest 3.1 以上版本,你可以直接实现RepositoryRestConfigurer

@Configuration
public class ConfigRepositoryRest implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.getCorsRegistry()
            .addMapping("/**")
            .allowedOrigins("http://localhost:3000");
}
Run Code Online (Sandbox Code Playgroud)

}