Spring MVC le permite manejar CORS (intercambio de recursos entre orígenes).
Por razones de seguridad, los navegadores prohíben las llamadas AJAX a recursos fuera del origen actual. Por ejemplo, es posible que tengas tu cuenta bancaria en una pestaña y evil.com en otra. Los scripts de evil.com no deberían poder realizar solicitudes AJAX a la API de su banco con sus credenciales; por ejemplo, ¡retirar dinero de su cuenta!
El intercambio de recursos entre orígenes (CORS) es especificación W3C implementada en la mayoría de los navegadores, lo que le permite determinar qué solicitudes entre dominios están permitidas, en lugar de utilizar soluciones alternativas menos seguras y menos potentes basadas en IFRAME o JSONP.
Procesamiento
La especificación CORS distingue entre solicitudes de verificación previa, simples y reales. Para comprender cómo funciona CORS, puede leer este artículo. otras cosas, o consulte la especificación para obtener más detalles.
Las implementaciones HandlerMapping
de Spring WebFlux brindan soporte CORS nativo. Después de asignar con éxito una solicitud a un controlador, HandlerMapping
verifica la configuración CORS para esa solicitud y controlador y toma medidas adicionales. Las solicitudes preliminares se procesan directamente, mientras que las solicitudes CORS simples y reales se interceptan, validan y se establecen los encabezados de respuesta CORS requeridos.
Para permitir solicitudes entre diferentes orígenes (es decir, el encabezado Origin
está presente y es diferente del host de solicitud), debe proporcionar alguna configuración CORS declarada explícitamente. Si no se encuentra una configuración CORS adecuada, se rechazan las solicitudes de verificación previa. Las respuestas a solicitudes CORS simples y reales no tienen encabezados CORS agregados y, por lo tanto, los navegadores las rechazan.
Cada HandlerMapping
puede ser configurado individualmente usando asignaciones CorsConfiguration
basadas en patrones de URL. En la mayoría de los casos, las aplicaciones utilizan la configuración Java de WebFlux para declarar estas asignaciones, lo que da como resultado un único mapa global pasado a todas las implementaciones de HandlerMapping
.
Puedes combinar la configuración CORS global en el nivel HandlerMapping
con un ajuste CORS más detallado en el nivel del controlador. Por ejemplo, los controladores anotados pueden usar anotaciones @CrossOrigin
a nivel de clase o método (otros controladores pueden implementar CorsConfigurationSource
).
Las reglas para combinar reglas globales y la configuración local suelen ser aditivas; por ejemplo, todas las fuentes globales y todas las locales. Para atributos donde solo se puede aceptar un valor, como allowCredentials
y maxAge
, el valor local anula el global. Para obtener más información, consulte la sección sobre CorsConfiguration#combine(CorsConfiguration)
.
Para obtener más información de la fuente original o realizar una configuración avanzada, consulte:
CorsConfiguration
CorsProcessor
yDefaultCorsProcessor
AbstractHandlerMapping
@CrossOrigin
Anotación @CrossOrigin
permite consultas entre diferentes fuentes a métodos de controlador anotados, como se muestra en el siguiente ejemplo:
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public Mono<Void> remove(@PathVariable Long id) {
// ...
}
}
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin
@GetMapping("/{id}")
suspend fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
suspend fun remove(@PathVariable id: Long) {
// ...
}
}
De forma predeterminada, @CrossOrigin
permite:
Todas las fuentes.
Todos los encabezados.
Todos los métodos HTTP que utiliza el método asociado con el controlador.
allowCredentials
no está habilitado de forma predeterminada porque establece el nivel de confianza en el que la información confidencial del usuario (como cookies y CSRF) tokens), por lo que sólo debe utilizarse en los casos en los que sea realmente necesario. Si está habilitado, entonces se debe configurar allowOrigins
para uno o más dominios específicos (pero no el valor especial "*"
) o, alternativamente, la propiedad enableOriginPatterns se puede usar para asignaciones. a un conjunto dinámico de fuentes.
maxAge
está establecido en 30 minutos.
@CrossOrigin
es compatible tanto en la clase nivel y es heredado por todos los métodos. El siguiente ejemplo especifica un dominio específico y establece maxAge
en una hora:
@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public Mono<Void> remove(@PathVariable Long id) {
// ...
}
}
@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) {
// ...
}
}
Puede utilizar la anotación @CrossOrigin
tanto a nivel de clase como de método, como se muestra en el siguiente ejemplo:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public Mono<Void> remove(@PathVariable Long id) {
// ...
}
}
- Usando un anotación
@CrossOrigin
a nivel de clase. - Usando la anotación
@CrossOrigin
a nivel de método.
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
suspend fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
suspend fun remove(@PathVariable id: Long) {
// ...
}
}
- Usando
@CrossOrigin
anotación a nivel de clase. - Usando la anotación
@CrossOrigin
a nivel de método.
Configuración global
Además del ajuste fino a nivel del método del controlador, es probable que también necesite definir la configuración CORS global. Puede configurar asignaciones CorsConfiguration
basadas en URL individualmente para cualquier HandlerMapping
. Sin embargo, la mayoría de las aplicaciones utilizan la configuración Java de WebFlux para esto.
De forma predeterminada, la configuración global incluye lo siguiente:
Todas las fuentes.
Todos los encabezados.
Métodos
GET
,HEAD
yPOST
.
allowCredentials
no está habilitado de forma predeterminada porque establece el nivel de confianza en el que la información confidencial del usuario (como cookies y CSRF) ) son tokens revelados), por lo que solo debe usarse en casos donde sea realmente necesario. Si está habilitado, entonces allowOrigins
debe configurarse para uno o más dominios específicos (pero no el valor especial "* "
), o alternativamente puede usar la propiedad enableOriginPatterns para comparar con un conjunto dinámico de orígenes.
maxAge
está establecido en 30 minutos.
Para habilitar CORS en la configuración de WebFlux Java, puede usar la devolución de llamada CorsRegistry
, como se muestra en el siguiente ejemplo:
@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);
// Agregar más pantallas...
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600)
// Agregar más pantallas...
}
}
WebFilter
para CORS
Puede aplicar compatibilidad con CORS a través del CorsWebFilter
lo cual es excelente para puntos finales funcionales.
CorsFilter
con Spring Security, tenga en cuenta que Spring Security proporciona
soporte integrado CORS.
Para configurar un filtro, puede declarar un bean CorsWebFilter
y pasar CorsConfigurationSource
a su constructor, como se muestra en el siguiente ejemplo:
@Bean
CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// Quizás...
// 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);
}
@Bean
fun corsFilter(): CorsWebFilter {
val config = CorsConfiguration()
// Quizás...
// config.applyPermitDefaultValues()
config.allowCredentials = true
config.addAllowedOrigin("https://domain1.com")
config.addAllowedHeader("*")
config.addAllowedMethod("*")
val source = UrlBasedCorsConfigurationSource().apply {
registerCorsConfiguration("/**", config)
}
return CorsWebFilter(source)
}
GO TO FULL VERSION