Java Spring Data Rest 和 Cors

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31724994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:31:04  来源:igfitidea点击:

Spring Data Rest and Cors

javaspringspring-mvccorsspring-data-rest

提问by Thomas Letsch

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

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

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

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

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

请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问Origin ' http://localhost:63343'。

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?

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

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:

我什至尝试为每个注释设置 Cors:

@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

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

What do I miss?

我想念什么?

采纳答案by Sébastien Deleuze

Indeed, before Spring Data REST 2.6 (Ingalls) only HandlerMappinginstances created by Spring MVC WebMvcConfigurationSupportand controllers annotated with @CrossOriginwere CORS aware.

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

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

但是现在DATAREST-573已修复,RepositoryRestConfiguration现在公开了getCorsRegistry()全局设置,并且@CrossOrigin存储库上的注释也被识别,因此这是推荐的方法。有关具体示例,请参阅https://stackoverflow.com/a/42403956/1092077答案。

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 CorsFilterthat use the same CORS processing logic that @CrossOriginand addCorsMappings(CorsRegistry registry)approaches. By passing an UrlBasedCorsConfigurationSourceinstance to the CorsFilterconstructor parameter, you could easily get something as powerful as Spring native CORS global support.

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

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

如果您使用的是 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;
    }
}

回答by Andrew Tobilko

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

自从实现了 Ingalls train 之后,Spring Data 中 CORS 的支持就开始了。有两种处理方式:

  1. The @CrossOriginannotation with specifying origins, methods, and allowedHeadersover a @RepositoryRestResourceinterface.

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long> { ... }
    
  2. A global configuration with the RepositoryRestConfigurationinside a @Configurationclass. Marking repositories by the @CrossOriginis 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);
         }
    
    }
    
  1. 在接口@CrossOrigin上指定originsmethods和的注释。allowedHeaders@RepositoryRestResource

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long> { ... }
    
  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);
         }
    
    }
    

回答by Johannes Rudolph

For some reason the approach suggested in the accepted answer above didn't work for me after upgrading from Spring Boot 1.5.2 to 1.5.6.

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

As also pointed out by @BigDong's comment, the exception I got was:

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

BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeExcep??tion: 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

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

So here's what I came up with to get a "global" CORS configuration for all endpoint in our REST API, whether they're implemented using Spring Data Rest or Spring MVC, with all endpoints protected by Spring Security.

因此,这就是我为 REST API 中的所有端点获取“全局”CORS 配置的想法,无论它们是使用 Spring Data Rest 还是 Spring MVC 实现的,所有端点都受 Spring Security 保护。

I wasn't able to hook a CorsFilterinto the request pipeline at the right point, so instead I configured SDR and MVC separately, however using the same configuration for their CorsRegistryvia this helper:

我无法CorsFilter在正确的点将a 连接到请求管道中,因此我分别配置了 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));
}

And then for MVC:

然后对于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 SDR:

然后对于 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's some further reference on the subject that helped me come up with this answer:

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

回答by asifaftab87

I was trying to hitting spring rest service from angular. Spring rest project deployed in tomcat server and angular is default angular server. I faced this issue when it is hitting from angular to service. I tried to follow

我试图从 angular 达到弹簧休息服务。Spring rest 项目部署在 tomcat 服务器中,angular 是默认的 angular 服务器。当它从角度击中到服务时,我遇到了这个问题。我试着跟随

https://juristr.com/blog/2016/11/configure-proxy-api-angular-cli/

https://juristr.com/blog/2016/11/configure-proxy-api-angular-cli/

but problem still there. Thanks to my senior 'Abbas bhai', he suggested please add some configuration in spring configuration file to avoid this problem, so I added this code in spring configuration.

但问题仍然存在。感谢我的前辈'Abbas bhai',他建议请在spring配置文件中添加一些配置来避免这个问题,所以我在spring配置中添加了这段代码。

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
@ComponentScan("org.liferayasif.backend")
public class RestConfig extends WebMvcConfigurerAdapter{

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
        configurer.enable();
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
     * To avoid 'Access-Control-Allow-Origin'
     * Above error arising when I am hitting from angular to our rest service
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

}

This method resolved my 'Access-Control-Allow-Origin' cors.

这种方法解决了我的“访问控制允许来源”问题。

@Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

For reference can download my whole project

作为参考可以下载我的整个项目

My github url link:

我的 github 网址链接:

https://github.com/asifaftab87/SpringPersistenceHibernate

https://github.com/asifaftab87/SpringPersistenceHibernate

Branch - security

分公司-安全

Project - Model

项目 - 模型

回答by Fazel Farnia

RepositoryRestConfigurerAdapteris deprecated from 3.1 so if you used spring boot and data-rest version 3.1 above you can directly implement RepositoryRestConfigurer:

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

}

}