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
)。
全局和本地配置的规则通常是相加的,但是有一些例外情况。对于那些只能接受一个值的属性,如 allowCredentials
和maxAge
,本地配置将覆盖全局配置。
@CrossOrigin
@CrossOrigin
可以让 controller
中带有该注解的方法进行跨域请求
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
}
默认情况下:
@Crossorigin
允许所有origin
、所有header
。allowCredentials
默认不启用。避免暴露敏感的用户信息(如cookies
和CSRF
令牌),应该只在适当的时候使用。当被启用时候,必须将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 支持,这与 函数式端点 很契合。
@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);
}
最后更新于
这有帮助吗?