spring-tutorial/docs/01.Java/13.框架/01.Spring/03.SpringWeb/05.Spring跨域.md

7.7 KiB
Raw Permalink Blame History

title date categories tags permalink
Spring MVC 之跨域 2023-02-16 20:33:26
Java
框架
Spring
SpringWeb
Java
框架
Spring
Web
CORS
/pages/1d2954/

Spring MVC 之跨域

Spring MVC 支持跨域处理CORS

简介

出于安全原因,浏览器禁止对当前源之外的资源进行 AJAX 调用。例如,可以在一个选项卡中使用您的银行帐户,而在另一个选项卡中使用 evil.com。来自 evil.com 的脚本不应该能够使用您的凭据向您的银行 API 发出 AJAX 请求——例如从您的账户中取款!

跨域CORS是由 大多数浏览器 实施的 W3C 规范,可让您指定哪种跨域请求是授权,而不是使用基于 IFRAME 或 JSONP 的不太安全和不太强大的解决方法。

处理

CORS 规范分为预检请求、简单请求和实际请求。要了解 CORS 的工作原理,可以阅读 Cross-Origin Resource Sharing (CORS) 等,或者查看规范了解更多详细信息。

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

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

每个 HandlerMapping 都可以[配置](https://docs.spring.io/spring-framework/docs/6.0.4/javadoc-api/org/springframework/web/servlet/handler/AbstractHandlerMapping.html#setCorsConfigurations- java.util.Map-) 单独使用基于 URL 模式的 CorsConfiguration 映射。 在大多数情况下,应用程序使用 MVC Java 配置或 XML 命名空间来声明此类映射,这会导致将单个全局映射传递给所有 HandlerMapping 实例。

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

The rules for combining global and local configuration are generally additivefor example, all global and all local origins. For those attributes where only a single value can be accepted, e.g. allowCredentials and maxAge, the local overrides the global value.

结合全局和局部配置的规则通常是附加的⟩——例如,所有全局和所有局部起源。 对于那些只能接受单个值的属性,例如 allowCredentialsmaxAge,局部覆盖全局值。

@CrossOrigin

@CrossOrigin 注解在带注解的 Controller 方法上启用跨源请求,如以下示例所示:

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

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

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

默认,@CrossOrigin 允许访问:

  • 所以 origin
  • 所以 header
  • 所以 Controller 方法映射到的 HTTP 方法

allowCredentials 默认情况下不启用,因为它建立了一个信任级别,可以公开敏感的用户特定信息(例如 cookie 和 CSRF 令牌),并且只应在适当的情况下使用。启用时,必须将 allowOrigins 设置为一个或多个特定域(但不是特殊值 "*"),或者 allowOriginPatterns 属性可用于匹配一组动态来源。

maxAge 单位为分钟

@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) {
        // ...
    }
}

全局配置

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

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

  • 所以 origin
  • 所以 header
  • GETHEADPOST 方法

allowCredentials 默认情况下不启用,因为它建立了一个信任级别,可以公开敏感的用户特定信息(例如 cookie 和 CSRF 令牌),并且只应在适当的情况下使用。启用时,必须将 allowOrigins 设置为一个或多个特定域(但不是特殊值 "*"),或者 allowOriginPatterns 属性可用于匹配一组动态来源。

maxAge 单位为分钟

Java 配置

要在 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 配置

要在 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>

CORS 过滤器

可以通过 Spring 内置的 CorsFilter 支持 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);

参考资料