CORS

简介

出于安全考虑,浏览器禁止 AJAX 调用当前来源以外的资源。例如,你可以将你的银行账户放在一个标签页中,而将 evil.com 放在另一个标签页中。evil.com 的脚本不应该能够用你的凭证向您的银行 API 发出AJAX 请求,例如,从您的账户中取款!

跨域资源共享(CORS)是由 大多数浏览器 实施的 W3C规范,它让你指定哪种跨域请求被授权,而不是使用基于 IFRAME 或 JSONP 的不太安全和不太强大的变通方法。

处理

CORS 规范区分了预检、简单和实际请求,要了解 CORS 的工作原理,请参考MDN

Spring WebFlux HandlerMapping 的实现提供了对 CORS 的支持。在成功地将一个请求映射到一个 handler 后,HandlerMapping 会检查给定的请求和 handler 的 CORS 配置,并采取进一步行动。预检请求(OPTIONS)会被直接处理,而简单请求和 CORS 请求被拦截、验证,并设置所需的 CORS 响应头。

每个 HandlerMapping 都可以单独配置基于 URL pattern 的 CorsConfiguration。在大多数情况下,应用程序使用 WebFlux 的 Java 配置来声明这种映射,这导致一个单一的、全局的映射传递给所有 HandlerMapping 实例。

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

全局和本地配置的规则通常是相加的,但是有一些例外情况。对于那些只能接受一个值的属性,如 allowCredentialsmaxAge,本地配置将覆盖全局配置。

@CrossOrigin

@CrossOrigin 可以让 controller 中带有该注解的方法进行跨域请求

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

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

默认情况下:

  • @Crossorigin 允许所有 origin、所有header

  • allowCredentials 默认不启用。避免暴露敏感的用户信息(如 cookiesCSRF 令牌),应该只在适当的时候使用。当被启用时候,必须将 allowOrigins 设置为一个或多个特定的域(不能是特殊值 "*"),或者可以使用 allowOriginPatterns 属性来匹配一组动态的 origin

  • maxAge 被设置为 30 分钟。

  • controller 中的 @CrossOrigin 注解被映射到所有 HTTP 方法。

@CrossOrigin 在类的层面上也被支持,并被所有方法继承。下面的例子指定了一个特定的域,并将 maxAge 设置为一个小时:

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

    @GetMapping("/{id}")
    suspend fun retrieve(@PathVariable id: Long): Account {
        // ...
    }

    @DeleteMapping("/{id}")
    suspend fun remove(@PathVariable id: Long) {
        // ...
    }
}

全局配置

在默认情况下,全局配置会启动以下功能:

  • 允许所有 origin

  • 允许所有 header

  • GET、HEAD 和 POST 方法

  • allowCredentials 默认不启用。避免暴露敏感的用户信息(如 cookies 和 CSRF 令牌),应该只在适当的时候使用。当被启用时候,必须将 allowOrigins 设置为一个或多个特定的域(不能是特殊值 "*"),或者可以使用 allowOriginPatterns 属性来匹配一组动态的 origin。

  • maxAge 被设置为 30 分钟。

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

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @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...
    }
}

CORS WebFilter

你可以通过内置的 CorsWebFilter 来应用 CORS 支持,这与 函数式端点 很契合。

如果你试图在 Spring Security 中使用 CorsFilter,请记住,Spring Security 有 内置支持的 CORS。

@Bean
CorsWebFilter corsFilter() {

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

    return new CorsWebFilter(source);
}

最后更新于

这有帮助吗?