由于标准标题

时间:2016-07-21 14:44:43

标签: spring cors

在调试CORS问题时遇到的问题我发现了以下行为。 Chrome会执行以下OPTIONS预检请求(由Chrome本身在CURL中重写):

curl -v 'https://www.example.com/api/v1/users' -X OPTIONS -H 'Access-Control-Request-Method: POST' -H 'Origin: http://example.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: es-ES,es;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36' -H 'Accept: */*' -H 'Referer: http://example.com/users/new' -H 'Connection: keep-alive' -H 'Access-Control-Request-Headers: accept, x-api-key, content-type'

如果出现以下情况,服务器对此请求的响应:

< HTTP/1.1 403 Forbidden
< Date: Thu, 21 Jul 2016 14:16:56 GMT
* Server Apache/2.4.7 (Ubuntu) is not blacklisted
< Server: Apache/2.4.7 (Ubuntu)
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains
< X-Frame-Options: SAMEORIGIN
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
< Content-Length: 20
< Keep-Alive: timeout=5, max=100
< Connection: Keep-Alive

作为回复的主体&#39;无效的CORS请求&#39;。如果我重复请求删除标题&#39; Access-Control-Request-Method&#39; (并且只有那个标题)OPTIONS请求成功,并带有以下响应:

< HTTP/1.1 200 OK
< Date: Thu, 21 Jul 2016 14:21:27 GMT
* Server Apache/2.4.7 (Ubuntu) is not blacklisted
< Server: Apache/2.4.7 (Ubuntu)
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains
< X-Frame-Options: SAMEORIGIN 
< Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with, x-api-key
< Access-Control-Max-Age: 60
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Allow-Origin: *
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
< Content-Length: 0
< Keep-Alive: timeout=5, max=100
< Connection: Keep-Alive

但是,违规标题是CORS spec standard header,所以它不应该阻止请求成功,对吧?为什么这个标题导致了这种行为?

我如何调整服务器发送的访问控制标头,以便在使用Chrome时使请求正常工作?

顺便说一下,我使用的是Chrome 36.0,服务器正在使用Spring Boot,其中CORS标头由Spring管理。

当Firefox(v47.0)发出请求时,行为会有所不同,但会产生模拟结果。 Firefox甚至不发送预检请求,它直接发送POST请求,作为响应接收403 Forbidden。但是,如果我将复制请求复制为cURL&#39;选项,并从终端窗口重复它,它成功并在响应中发送正确的CORS标头。

有什么想法吗?

更新:Firefox会发送预检OPTIONS请求(如Live HTTP标头插件所示),但Firebug会屏蔽它,因此两个浏览器中的行为完全相同。在这两种浏览器中都有“访问控制 - 请求 - 方法”。标题使得请求失败的差异。

7 个答案:

答案 0 :(得分:25)

经过大量的挣扎,我终于找到了问题所在。我在Spring中配置了一个请求映射来处理OPTIONS流量,如下所示:

@RequestMapping(value= "/api/**", method=RequestMethod.OPTIONS)
public void corsHeaders(HttpServletResponse response) {
    response.addHeader("Access-Control-Allow-Origin", "*");
    response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    response.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
    response.addHeader("Access-Control-Max-Age", "3600");
}

我不知道默认情况下Spring使用default CORS processor,似乎它干扰了我的请求映射。删除我的请求映射并将@CrossOrigin注释添加到适当的请求映射中解决了这个问题。

答案 1 :(得分:16)

我也遇到了同样的问题,并找到了在春季启动时启用全球角色问题的解决方案

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
                .allowedHeaders("*");
    }
}
在此之后,我们还需要在spring安全级别启用CORS,为此 在SecurityConfiguration类中添加cors(),其范围为WebSecurityConfigurerAdapter

 @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
                .cors()
                .and()
                .csrf().disable()
                .authorizeRequests()..

    }

答案 2 :(得分:6)

我有同样的问题。我通过在Spring MVC配置中为允许的CORS方法添加'OPTIONS'来解决它。

@Configuration
@EnableWebMvc
@ComponentScan
public class RestApiServletConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        super.addCorsMappings(registry);
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000", "http://localhost:8080")
                .allowedMethods("GET", "PUT", "POST", "DELETE", "OPTIONS");
    }
}

答案 3 :(得分:2)

要使其在具有安全性的Spring Boot中正常工作,我必须:

1。启用调度选项请求

在application.yml中:

spring.mvc.dispatch-options-request: true

2。定义CORS配置源:

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Collections.singletonList("*"));
    configuration.setAllowedMethods(Collections.singletonList("*"));
    configuration.setAllowedHeaders(Collections.singletonList("*"));
    configuration.setExposedHeaders(Collections.singletonList(HttpHeaders.LOCATION));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource()
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

3。在安全配置中启用CORS

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .cors()
            .and()
            .authorizeRequests()
            // More security configuration here
}

答案 4 :(得分:1)

我添加了这个作为答案,因为我无法将其格式化为最佳投票答案。

我发现这篇文章也很有用:How to handle HTTP OPTIONS with Spring MVC?

必须将DispatchServlet配置为传递选项请求,否则它永远不会到达映射的请求:

...
  <servlet>
    <servlet-name>yourServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>dispatchOptionsRequest</param-name>
      <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
...

答案 5 :(得分:1)

对我来说,我在每个控制器api调用中都添加了@crossorigin注释。

@CrossOrigin
@PostMapping(path = "/getListOfIndividuals", produces = { "application/json" }, consumes = { "application/json" })
public ResponseEntity<String> test(@RequestBody String viewIndividualModel)
        throws Exception {
    String individualDetails = globalService.getIndividualDetails(viewIndividualModel);


    finalString = discSpecAssmentService.getViewFormForDisciplineEvaluation( viewIndividualModel);

    return new ResponseEntity<String>(finalString, HttpStatus.OK);
}

答案 6 :(得分:0)

我确实在使用test-cors.org网站在端点上测试CORS时遇到了这个问题,它表现出与上述完全相同的行为。

我做的方法是使用Global CORS过滤器而不是使用@CrossOrigin注释。

@Configuration
class CorsConfig : WebMvcConfigurer {
    override fun addCorsMappings(registry: CorsRegistry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedHeaders("*")
                .allowedMethods("*")
                .allowedOrigins("*")
                .maxAge(3600)
    }
}

请注意,除非您要按照here中所述控制Spring Boot自动配置,否则不应该使用@EnableWebMvc……这可能会引起here中所述的“问题”和here

还需要 下一个自定义配置(解决方案从here部分取消),否则您将收到特定的CORS飞行前问题:

@Configuration
class CustomWebSecurityConfigurerAdapter : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http.cors().and().csrf().disable()
    }
}