CORS con primavera

1. Información general

En cualquier navegador moderno, Cross-Origin Resource Sharing (CORS) es una especificación relevante con la aparición de clientes HTML5 y JS que consumen datos a través de API REST.

En muchos casos, el host que sirve a JS (por ejemplo, example.com ) es diferente del host que sirve los datos (por ejemplo, api.example.com ). En tal caso, CORS permite la comunicación entre dominios.

Spring proporciona soporte de primera clase para CORS, ofreciendo una forma fácil y poderosa de configurarlo en cualquier aplicación web Spring o Spring Boot.

2. Configuración de CORS del método de controlador

Habilitar CORS es sencillo: solo agregue la anotación @CrossOrigin .

Podemos implementar esto de varias formas diferentes.

2.1. @CrossOrigin en un @ RequestMapping- Método de controlador anotado

@RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @RequestMapping(method = RequestMethod.GET, path = "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }

En el ejemplo anterior, solo habilitamos CORS para el método retrieve () . Podemos ver que no establecimos ninguna configuración para la anotación @CrossOrigin , por lo que usa los valores predeterminados:

  • Se permiten todos los orígenes
  • Los métodos HTTP permitidos son los especificados en la anotación @RequestMapping (para este ejemplo es GET)
  • El tiempo que se almacena en caché la respuesta de verificación previa ( maxAge) es de 30 minutos

2.2. @CrossOrigin en el controlador

@CrossOrigin(origins = "//example.com", maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @RequestMapping(method = RequestMethod.GET, path = "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }

Esta vez, agregamos @CrossOrigin a nivel de clase. En consecuencia, tanto los métodos retrieve () como remove () lo tienen habilitado. Podemos personalizar la configuración especificando el valor de uno de los atributos de anotación: orígenes , métodos , permitidosHeaders , expuestosHeaders , allowCredentials o maxAge.

2.3. @CrossOrigin en el método de controlador y controlador

@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("//example.com") @RequestMapping(method = RequestMethod.GET, "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }

Spring combinará atributos de ambas anotaciones para crear una configuración CORS fusionada.

En este ejemplo, ambos métodos tendrán una edad máxima de 3600 segundos, el método remove () permitirá todos los orígenes, pero el método retrieve () solo permitirá los orígenes de //example.com.

3. Configuración CORS global

Como alternativa a la configuración fina basada en anotaciones, Spring nos permite definir alguna configuración CORS global de sus controladores. Esto es similar a usar una solución basada en filtros , pero puede declararse dentro de Spring MVC y combinarse con una configuración detallada de @CrossOrigin .

De forma predeterminada, se permiten todos los orígenes y métodos GET, HEAD y POST.

3.1. JavaConfig

@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); } }

El ejemplo anterior habilita las solicitudes CORS desde cualquier origen a cualquier punto final de la aplicación.

Si queremos bloquear esto un poco más, el método registry.addMapping devuelve un objeto CorsRegistration , que podemos usar para una configuración adicional. También hay un método allowedOrigins que nos permite especificar una matriz de orígenes permitidos. Esto puede ser útil si necesitamos cargar esta matriz desde una fuente externa en tiempo de ejecución.

Además, también hay allowedMethods , allowedHeaders , posedHeaders , maxAge y allowCredentials que podemos utilizar para configurar los encabezados de respuesta y las opciones de personalización.

3.2. Espacio de nombres XML

Esta configuración XML mínima habilita CORS en un patrón de ruta / ** con las mismas propiedades predeterminadas que JavaConfig:

También es posible declarar varias asignaciones CORS con propiedades personalizadas:

4. CORS con Spring Security

Si usamos Spring Security en nuestro proyecto, debemos dar un paso adicional para asegurarnos de que funcione bien con CORS. Es porque CORS debe procesarse primero. De lo contrario, Spring Security rechazará la solicitud antes de que llegue a Spring MVC.

Afortunadamente, Spring Security ofrece una solución lista para usar:

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and()... } }

Este artículo lo explica con más detalle.

5. Cómo funciona

Las solicitudes CORS se envían automáticamente a los diversos HandlerMappings registrados . Manejan las solicitudes de verificación previa de CORS e interceptan las solicitudes simples y reales de CORS utilizando una implementación de CorsProcessor ( DefaultCorsProcessor de forma predeterminada) para agregar los encabezados de respuesta CORS relevantes (como Access-Control-Allow-Origin ).

CorsConfiguration nos permite especificar cómo se deben procesar las solicitudes CORS: orígenes permitidos, encabezados y métodos, entre otros. Podemos proporcionarlo de varias formas:

  • AbstractHandlerMapping # setCorsConfiguration () permite especificar un mapa con varios CorsConfiguration asignados a patrones de ruta como / api / **
  • Las subclases pueden proporcionar su propia CorsConfiguration reemplazando el AbstractHandlerMapping # getCorsConfiguration (Object, HttpServletRequest) método
  • Los controladores pueden implementar la interfaz CorsConfigurationSource (como ahora lo hace ResourceHttpRequestHandler ) para proporcionar una CorsConfiguration para cada solicitud

6. Conclusión

En este artículo, mostramos cómo Spring brinda soporte para habilitar CORS en nuestra aplicación.

Empezamos con la configuración del controlador. Vimos que solo necesitamos agregar la anotación @CrossOrigin para habilitar CORS ya sea para un método en particular o para todo el controlador.

Finalmente, también vimos que si queremos controlar la configuración de CORS fuera de los controladores, podemos hacerlo sin problemas en los archivos de configuración, ya sea usando JavaConfig o XML.

El código fuente completo de los ejemplos está disponible en GitHub.