CORS with Spring – 使用Spring的CORS

最后修改: 2017年 1月 30日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In any modern browser, Cross-Origin Resource Sharing (CORS) is a relevant specification with the emergence of HTML5 and JS clients that consume data via REST APIs.

在任何现代浏览器中,跨源资源共享(CORS)是一个相关的规范,随着HTML5和JS客户端的出现,通过REST APIs消费数据。

Often, the host that serves the JS (e.g. example.com) is different from the host that serves the data (e.g. api.example.com). In such a case, CORS enables cross-domain communication.

通常,提供JS的主机(例如example.com)与提供数据的主机(例如api.example.com)不同。在这种情况下,CORS实现了跨域通信。

Spring provides first-class support for CORS, offering an easy and powerful way of configuring it in any Spring or Spring Boot web application.

Spring为CORS提供了一流的支持,为在任何Spring或Spring Boot Web应用程序中配置它提供了简单而强大的方法。

2. Controller Method CORS Configuration

2.控制器方法的CORS配置

Enabling CORS is straightforward — just add the annotation @CrossOrigin.

启用 CORS 很简单 – 只需添加注释 @CrossOrigin.

We can implement this in several different ways.

我们可以通过几种不同的方式来实现这一点。

2.1. @CrossOrigin on a @RequestMapping-Annotated Handler Method

2.1.@CrossOrigin关于@RequestMapping-注释的处理方法

@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET, path = "/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

In the example above, we only enabled CORS for the retrieve() method. We can see that we didn’t set any configuration for the @CrossOrigin annotation, so it uses the defaults:

在上面的例子中,我们只为retrieve()方法启用了 CORS。我们可以看到,我们没有为@CrossOrigin注解设置任何配置,所以它使用了默认值。

  • All origins are allowed.
  • The HTTP methods allowed are those specified in the @RequestMapping annotation (GET, for this example).
  • The time that the preflight response is cached (maxAge) is 30 minutes.

2.2. @CrossOrigin on the Controller

2.2.@CrossOrigin on the Controller

@CrossOrigin(origins = "http://example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @RequestMapping(method = RequestMethod.GET, path = "/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

This time, we added @CrossOrigin on the class level. So, both retrieve() and remove() methods have it enabled. We can customize the configuration by specifying the value of one of the annotation attributes: origins, methods, allowedHeaders, exposedHeaders, allowCredentials, or maxAge.

这一次,我们在类的层面上添加了@CrossOrigin。因此,retrieve()remove()方法都启用了它。我们可以通过指定其中一个注解属性的值来定制配置。originsmethodsallowedHeadersexposedHeadersallowCredentialsmaxAge

2.3. @CrossOrigin on Controller and Handler Method

2.3.@CrossOrigin关于控制器和处理程序方法

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin("http://example.com")
    @RequestMapping(method = RequestMethod.GET, "/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

Spring will combine attributes from both annotations to create a merged CORS configuration.

Spring将结合两个注解的属性来创建一个合并的CORS配置。

Here, both methods will have a maxAge of 3,600 seconds, the method remove() will allow all origins, and the method retrieve() will only allow origins from http://example.com.

这里,两个方法的maxAge都是3600秒,remove()方法将允许所有的起源,而retrieve()方法将只允许来自http://example.com的起源。

3. Global CORS Configuration

3.全局CORS配置

As an alternative to the fine-grained annotation-based configuration, Spring lets us define a global CORS configuration out of our controllers. This is similar to using a Filter-based solution but can be declared within Spring MVC and combined with a fine-grained @CrossOrigin configuration.

作为基于注解的细粒度配置的替代方案,Spring允许我们从控制器中定义一个全局CORS配置。这类似于使用基于Filter的解决方案,但可以在Spring MVC中声明并与细粒度的@CrossOrigin配置相结合。

By default, all origins and GET, HEAD, and POST methods are allowed.

默认情况下,允许所有起源和GET、HEAD和POST方法。

3.1. JavaConfig

3.1.JavaConfig

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

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

The example above enables CORS requests from any origin to any endpoint in the application.

上面的例子使CORS请求从任何来源到应用程序中的任何端点。

To lock this down a bit more, the registry.addMapping method returns a CorsRegistration object, which we can use for additional configuration. There’s also an allowedOrigins method that lets us specify an array of allowed origins. This can be useful if we need to load this array from an external source at runtime.

为了进一步锁定,registry.addMapping方法返回一个CorsRegistration对象,我们可以用它来进行额外的配置。还有一个allowedOrigins方法,让我们指定一个允许的起源数组。如果我们需要在运行时从外部来源加载这个数组,这可能很有用。

Additionally, there are also allowedMethods, allowedHeaders, exposedHeaders, maxAge and allowCredentials that we can use to set the response headers and customization options.

此外,还有allowedMethodsallowedHeadersexposedHeadersmaxAgeallowCredentials,我们可以用来设置响应头和定制选项。

It is worth noting that since version 2.4.0, Spring Boot introduced allowedOriginPatterns in addition to just allowedOrigins. This new element gives more flexibility when defining patterns. Furthermore, when allowCredentials is true, allowedOrigins cannot contain the special value ‘*’ since that cannot be set on the Access-Control-Allow-Origin response header. To solve this issue and allow the credentials to a set of origins, we can either list them explicitly or consider using allowedOriginPatterns instead.

值得注意的是,从2.4.0版本开始,Spring Boot在allowedOriginPatterns之外还引入了allowedOrigins。这个新元素在定义模式时提供了更多的灵活性。此外,当allowCredentials为真时,allowedOrigins不能包含特殊值’*’,因为这不能在Access-Control-Allow-Origin响应头中设置。为了解决这个问题,并允许对一组起源的凭证,我们可以明确地列出它们,或者考虑使用allowedOriginPatterns代替。

3.2. XML Namespace

3.2.XML名称空间

This minimal XML configuration enables CORS on a /** path pattern with the same default properties as the JavaConfig one:

这个最小的XML配置在/**路径模式上启用CORS,其默认属性与JavaConfig的相同。

<mvc:cors>
    <mvc:mapping path="/**" />
</mvc:cors>

It’s also possible to declare several CORS mappings with customized properties:

也可以用自定义的属性声明几个 CORS 映射。

<mvc:cors>

    <mvc:mapping path="/api/**"
        allowed-origins="http://domain1.com, http://domain2.com"
        allowed-methods="GET, PUT"
        allowed-headers="header1, header2, header3"
        exposed-headers="header1, header2" allow-credentials="false"
        max-age="123" />

    <mvc:mapping path="/resources/**"
        allowed-origins="http://domain1.com" />

</mvc:cors>

4. CORS With Spring Security

4.CORS与Spring Security

If we use Spring Security in our project, we must take an extra step to make sure it plays well with CORS. That’s because CORS needs to be processed first. Otherwise, Spring Security will reject the request before it reaches Spring MVC.

如果我们在项目中使用Spring Security,我们必须采取额外的步骤,以确保它与CORS发挥良好。这是因为CORS需要先被处理。否则,Spring Security会在请求到达Spring MVC之前拒绝该请求。

Luckily, Spring Security provides an out-of-the-box solution:

幸运的是,Spring Security提供了一个开箱即用的解决方案。

@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}

This article explains it in more detail.

这篇文章更详细地解释了它。

5. How It Works

5.它是如何工作的

CORS requests are automatically dispatched to the various registered HandlerMappings. They handle CORS preflight requests and intercept CORS simple and actual requests using a CorsProcessor implementation (DefaultCorsProcessor by default) to add the relevant CORS response headers (such as Access-Control-Allow-Origin).

CORS请求被自动派发到各种注册的HandlerMappings。它们处理 CORS 预检请求,并使用 CorsProcessor 实现(默认为 DefaultCorsProcessor)拦截 CORS 简单和实际请求,以添加相关的 CORS 响应头(如 Access-Control-Allow-Origin)。

CorsConfiguration allows us to specify how the CORS requests should be processed, including allowed origins, headers, and methods, among others. We can provide it in various ways:

CorsConfiguration允许我们指定应该如何处理 CORS 请求,包括允许的起源、标头和方法,等等。我们可以以各种方式提供。

  • AbstractHandlerMapping#setCorsConfiguration() allows us to specify a Map with several CorsConfigurations mapped onto path patterns such as /api/**.
  • Subclasses can provide their own CorsConfiguration by overriding the AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest) method.
  • Handlers can implement the CorsConfigurationSource interface (like ResourceHttpRequestHandler does now) to provide a CorsConfiguration for each request.

6. Conclusion

6.结论

In this article, we showed how Spring provides support for enabling CORS in our application.

在这篇文章中,我们展示了Spring如何为在我们的应用程序中启用CORS提供支持。

We started with the configuration of the controller. We saw that we only need to add the annotation @CrossOrigin to enable CORS to either one particular method or the entire controller.

我们从控制器的配置开始。我们看到,我们只需要添加注解@CrossOrigin,就可以为一个特定的方法或整个控制器启用CORS。

Also, we learned that in order to control the CORS configuration outside of the controllers, we can perform this smoothly in the configuration files using either JavaConfig or XML.

另外,我们还了解到,为了在控制器之外控制CORS配置,我们可以在配置文件中使用JavaConfig或XML顺利地完成这一工作。

The full source code for the examples is available over on GitHub.

例子的完整源代码可在GitHub上获得over