Spring5.1.x官方参考指南中文版

 主页   资讯   文章   代码   电子书 

1.6 CORS

Spring MVC使您可以处理CORS(跨域资源共享)。本节介绍如何执行此操作。

1.6.1 介绍

出于安全原因,浏览器禁止AJAX调用当前来源以外的资源。例如,您可以将您的银行帐户放在一个标签中,将evil.com放在另一个标签中。来自evil.com的脚本不能使用您的凭据向您的银行API发出AJAX请求,例如从您的帐户中提取资金!

跨域资源共享(CORS)是大多数浏览器实施的W3C规范,可让您指定授权哪种类型的跨域请求,而不是使用基于IFRAME或JSONP的安全性较低且功能较弱的变通办法。

1.6.2 Processing

CORS规范区分飞行前,简单和实际请求。要了解CORS的工作原理,您可以阅读本文以及其他内容,或者参阅规范以获取更多详细信息。

Spring MVC HandlerMapping实现为CORS提供内置支持。成功将请求映射到处理程序后,HandlerMapping实现将检查给定请求和处理程序的CORS配置,并采取进一步的措施。飞行前请求直接处理,而简单和实际的CORS请求被拦截,验证并设置了必需的CORS响应标头。

为了启用跨域请求(即存在Origin标头,并且与请求的主机不同),您需要具有一些显式声明的CORS配置。如果找不到匹配的CORS配置,则预检请求将被拒绝。没有将CORS标头添加到简单和实际CORS请求的响应中,因此,浏览器拒绝了它们。

可以使用基于URL模式的CorsConfiguration映射分别配置每个HandlerMapping。在大多数情况下,应用程序使用MVC Java配置或XML名称空间声明此类映射,这导致将单个全局映射传递给所有HandlerMappping实例。

您可以将HandlerMapping级别的全局CORS配置与更细粒度的处理程序级别的CORS配置结合使用。例如,带注解的控制器可以使用类或方法级别的@CrossOrigin注解(其他处理程序可以实现CorsConfigurationSource)。

全局和本地配置组合的规则通常是相加的,例如,所有全局和所有本地起源。对于只能接受单个值的那些属性(例如allowCredentials和maxAge),局部属性将覆盖全局值。有关更多详细信息,请参见CorsConfiguration#combine(CorsConfiguration)。

1.6.3 @CrossOrigin

@CrossOrigin批注启用带注解的控制器方法上的跨域请求,如以下示例所示:

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

    @CrossOrigin
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

默认情况下,@ CrossOrigin允许:

  • All origins.
  • All headers.
  • 控制器方法映射到的所有HTTP方法。

默认情况下,allowedCredentials未启用,因为它建立了一个信任级别,可以公开敏感的用户特定信息(例如cookie和CSRF令牌),并且仅在适当的地方使用。

maxAge设置为30分钟。

@CrossOrigin在类级别上也受支持,并且被所有方法继承,如以下示例所示:

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

    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

您可以在类级别和方法级别上使用@CrossOrigin,如以下示例所示:

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

    @CrossOrigin("https://domain2.com")
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

1.6.4 Global Configuration

除了细粒度的控制器方法级别配置外,您可能还想定义一些全局CORS配置。 您可以在任何HandlerMapping上分别设置基于URL的CorsConfiguration映射。 但是,大多数应用程序使用MVC Java配置或MVC XNM命名空间来执行此操作。

默认情况下,全局配置启用以下功能:

  • All origins.
  • All headers.
  • GET,HEAD和POST方法。

默认情况下,allowedCredentials未启用,因为它建立了一个信任级别,可以公开敏感的用户特定信息(例如cookie和CSRF令牌),并且仅在适当的地方使用。

maxAge设置为30分钟。

Java Configuration

要在MVC Java配置中启用CORS,可以使用CorsRegistry回调,如以下示例所示:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
            .allowedOrigins("https://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(true).maxAge(3600);

        // Add more mappings...
    }
}

XML Configuration

要在XML名称空间中启用CORS,可以使用<mvc:cors>元素,如以下示例所示:

<mvc:cors>

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

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

</mvc:cors>

1.6.5 CORS Filter

您可以通过内置的CorsFilter应用CORS支持。

如果您尝试将CorsFilter与Spring Security一起使用,请记住Spring Security内置了对CORS的支持。

要配置过滤器,请将CorsConfigurationSource传递给其构造函数,如以下示例所示:

CorsConfiguration config = new CorsConfiguration();

// Possibly...
// config.applyPermitDefaultValues()

config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);

CorsFilter filter = new CorsFilter(source);