Spring MVC permite usted debe manejar CORS (intercambio de recursos entre orígenes).

Introducción

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 MVC proporcionan soporte CORS nativo. Después de asignar con éxito una solicitud a un controlador, las implementaciones de HandlerMapping verifican la configuración CORS para esa solicitud y controlador y toman 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 una configuración Java MVC o un espacio de nombres XML para declarar dichas asignaciones, lo que da como resultado que todas las instancias de HandlerMapping reciban un único mapa global.

Puedes combinar CORS global configuración 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 aquellos 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 sobre el código fuente o la configuración avanzada, consulte el código:

  • CorsConfiguration

  • CorsProcessor, DefaultCorsProcessor

  • AbstractHandlerMapping

@CrossOrigin

Anotación @CrossOrigin permite consultas entre diferentes fuentes a métodos de controlador anotados, como se muestra en el siguiente ejemplo:

Java

@RestController
@RequestMapping("/account")
public class AccountController {
    @CrossOrigin
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }
    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}
Kotlin

@RestController
@RequestMapping("/account")
class AccountController {
    @CrossOrigin
    @GetMapping("/{id}")
    fun retrieve(@PathVariable id: Long): Account {
        // ...
    }
    @DeleteMapping("/{id}")
    fun remove(@PathVariable id: Long) {
        // ...
    }
}

De forma predeterminada, @CrossOrigin permite:

  • Todas las fuentes.

  • Todos los encabezados.

  • Todos los métodos HTTP con los que está asociado el método del controlador.

allowCredentials no está habilitado de forma predeterminada, ya que esto establece el nivel de confianza en el que se divulga la información confidencial del usuario (como cookies y tokens CSRF), por lo que solo debe usarse en los casos en 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. frente a un conjunto dinámico de fuentes.

maxAge se establece en 30 minutos.

La @CrossOrigin anotación se admite en el nivel de clase y también se heredan todos los métodos, como se muestra en el siguiente ejemplo:

Java

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

@CrossOrigin(origins = ["https://domain2.com"], maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
    @GetMapping("/{id}")
    fun retrieve(@PathVariable id: Long): Account {
        // ...
    }
    @DeleteMapping("/{id}")
    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:

Java

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

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
    @CrossOrigin("https://domain2.com")
    @GetMapping("/{id}")
    fun retrieve(@PathVariable id: Long): Account {
        // ...
    }
    @DeleteMapping("/{id}")
    fun remove(@PathVariable id: Long) {
        // ...
    }
}

Configuración global

Además del ajuste fino en el controlador A nivel de método, probablemente necesitará definir la configuración global de CORS. Puede configurar asignaciones CorsConfiguration basadas en URL individualmente para cualquier HandlerMapping. Sin embargo, la mayoría de las aplicaciones utilizan la configuración MVC en Java o el espacio de nombres MVC en XML para hacer esto.

De forma predeterminada, la configuración global permite lo siguiente:

  • Todas las fuentes.

  • Todos los encabezados.

  • Métodos GET, HEAD y POST.

allowCredentials no está habilitado de forma predeterminada porque establece el nivel de confianza en el que se información del usuario (como cookies y tokens CSRF), por lo que solo debe usarse en los casos en 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. contra un conjunto dinámico de fuentes.

maxAge se establece en 30 minutos.

Configuración de Java

Para habilitar CORS en la configuración de Java MVC, puede utilizar la devolución de llamada CorsRegistry como se muestra en el siguiente ejemplo:

Java

@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);
        // Agregar más visualizaciones...
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    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 vistas...
    }
}

Configuración XML

Para habilitar CORS en un espacio de nombres XML, puede utilizar el elemento <mvc:cors>, como se muestra en la siguiente ejemplo:


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

filtro CORS

Puede aplicar compatibilidad con CORS a través del CorsFilter .

Si intenta utilizar CorsFilter con Spring Security, tenga en cuenta que Spring Security proporciona built -en soporte CORS.

Para configurar un filtro, pase CorsConfigurationSource a su constructor, como se muestra en el siguiente ejemplo:

Java

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);
CorsFilter filter = new CorsFilter(source);
Kotlin

val config = CorsConfiguration()
// Posiblemente...
// config.applyPermitDefaultValues()
config.allowCredentials = true config.addAllowedOrigin("https://domain1.com")
config.addAllowedHeader("*") config.addAllowedMethod("*")
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", config)
val filter = CorsFilter(source)