Spring Data Rest 和 Cors

Posted

技术标签:

【中文标题】Spring Data Rest 和 Cors【英文标题】:Spring Data Rest and Cors 【发布时间】:2015-10-21 21:11:17 【问题描述】:

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

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

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

经过一些调试,我发现以下内容: AbstractHandlerMapping.corsConfiguration 为除 RepositoryRestHandlerMapping 之外的所有子类填充。在 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");
    

   ...

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

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



原始请求标头:

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

原始响应标头:

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

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

我错过了什么?

【问题讨论】:

我不知道 Spring Boot,但我已经使用 Java 端的过滤器和 Dart 端的一些额外参数完成了它,请参阅 dart:***.com/questions/29427203/… 和 ***.com/questions/22846309/… 也发布一些网络跟踪,它可以更容易地查看实际发送和接收的内容。 过滤器应该不再需要恕我直言:***.com/a/31539691/1309964 - 对于 OPTIONS 请求,这已经有效。 听起来不错的新注释可以使用!查看您的响应标头,我希望看到以下我不是的标头:Access-Control-Allow-Credentials:true/false.Access-Control-Allow-Methods:GET, POST, OPTIONS, DELETEAccess-Control-Allow-Origin:http://____.comAccess-Control-Max-Age:60 我假设 Spring Boot 自动处理注释扫描或者您手动设置它?我假设这些注释位于某种控制器中,您是否有一个 @Controller 注释或一些告诉 spring 扫描该类的注释? 像这个例子一样,如果你把它直接放在你上面@Controller / @RestController 是否有效? spring.io/blog/2015/06/08/cors-support-in-spring-framework 这个提交应该可以解决问题:DATAREST-573 - Add support for new CORS configuration mechanisms intr…,它将包含在 2.6 版中 【参考方案1】:

确实,在 Spring Data REST 2.6 (Ingalls) 之前,只有由 Spring MVC WebMvcConfigurationSupport 创建的 HandlerMapping 实例和使用 @CrossOrigin 注释的控制器可以识别 CORS。

但是现在DATAREST-573 已经修复,RepositoryRestConfiguration 现在公开了一个用于全局设置的getCorsRegistry(),并且还可以识别存储库上的@CrossOrigin 注释,因此这是推荐的方法。具体例子见https://***.com/a/42403956/1092077答案。

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

如果您使用的是 Spring Boot(支持 Filter bean),它可能类似于:

@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;
    

【讨论】:

好的,它可以工作。但是我还不能使用它,因为我需要更多的灵活性/便利性 Access-Control-Allow-Origin :***.com/questions/32797633/… 为了使这项工作与 Spring-Security 一起工作,我不得不使用第一个解决方案并将 CorsFilter 添加到 Spring-Security 过滤器链中,如下所示:http.addFilterBefore(corsFilter, ChannelProcessingFilter.class) 出于某种原因,new CorsFilter(source) 会抛出运行时异常,所以我最终手动创建了一个 SimpleCorsFilter。但这个答案确实让我知道,当一切看起来都正确连接时,我并没有发疯。 我已将Spring + CORS blog post 更新为FilterRegistrationBean。请注意,支持config.addAllowedMethod("*") BeanInstantiationException:无法实例化 [javax.servlet.Filter]:工厂方法“springSecurityFilterChain”抛出异常;嵌套异常是 org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为“corsFilter”的 Bean 应为“org.springframework.web.filter.CorsFilter”类型,但实际上为“org.springframework.boot.web.servlet”类型.FilterRegistrationBean【参考方案2】:

自the Ingalls train has been realised 起,Spring Data 中对 CORS 的支持现已开启。有两种处理方式:

    @CrossOrigin 注释在@RepositoryRestResource 接口上指定originsmethodsallowedHeaders

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long>  ... 
    

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

【讨论】:

不知何故,第一种方法对我来说不适用于 JpaRepository,但第二种方法可以。有什么想法会导致这种情况吗? @dvdgsng,我可以看一下您尝试使用第一个选项的一段代码吗?这是一个房间chat.***.com/rooms/142423 谢谢!你从地狱的虫子中拯救了我的心理健康! 不幸的是,建议的解决方案都不适用于 Spring Boot 1.4.3 和 1.5.4 - Camden.SR4。第一个没有区别,第二个在RepositoryRestConfiguration中找不到getCorsRegistry方法。【参考方案3】:

由于某种原因,在从 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));

然后对于 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);
            
        ;
    

然后是 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());

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

https://spring.io/blog/2015/06/08/cors-support-in-spring-framework https://docs.spring.io/spring-security/site/docs/current/reference/html/cors.html

【讨论】:

【参考方案4】:

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

【讨论】:

感激不尽!!!这适用于 2.3.4.RELEASE 和 reactjs (axios)。那么如何在 Spring Boot 教程/文档中找到这样的解决方案呢? @CrossOrigina 注释似乎不适用于数据存储库。我花了两天时间寻找解决方案,这就是答案。我错过了什么? 这成功了!我正在尝试使用 @Bean public WebMvcConfigurer corsConfigurer() 的类似方法,但未能成功。 只是补充一下,这是根据文档docs.spring.io/spring-data/rest/docs/current/reference/html/…在“自定义Spring Data REST”章节“配置CORS”下的推荐方式。【参考方案5】:

我试图从 Angular 中获得弹簧休息服务。 Spring rest 项目部署在 tomcat 服务器中,angular 是默认的 angular 服务器。 当它从角度到服务时,我遇到了这个问题。 我试图关注

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

但问题仍然存在。 感谢我的前辈'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("/**");
    


此方法解决了我的“Access-Control-Allow-Origin”问题。

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

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

我的 github 网址链接:

https://github.com/asifaftab87/SpringPersistenceHibernate

分支 - 安全

项目 - 模型

【讨论】:

以上是关于Spring Data Rest 和 Cors的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data Rest 和 Cors

Spring Data REST (2.4.4.RELEASE) 和 CORS

spring-data-rest 和控制器,使用相同的 objectMaper 进行序列化/反序列化

Spring Data Rest 和 Hateoas

Spring Data REST

将业务逻辑添加到 spring-data-rest 应用程序