Confundido sobre cómo manejar las solicitudes de verificación previa de CORS OPTIONS

Soy nuevo en el trabajo con Cross Origin Resource Sharing y trato de que mi aplicación web responda a las solicitudes CORS. Mi aplicación web es una aplicación Spring 3.2 que se ejecuta en Tomcat 7.0.42.

En el web.xml de mi webapp, he habilitado el filtro Tomcat CORS:

   CorsFilter org.apache.catalina.filters.CorsFilter   CorsFilter /*  

Mi cliente (escrito con AngularJS 1.2.12) intenta acceder a un punto final REST con la Autenticación básica habilitada. Cuando hace su solicitud GET, Chrome realiza la verificación previa de la solicitud, pero recibe una respuesta Prohibida 403 del servidor:

 Request URL:http://dev.mydomain.com/joeV2/users/listUsers Request Method:OPTIONS Status Code:403 Forbidden Request Headers: OPTIONS /joeV2/users/listUsers HTTP/1.1 Host: dev.mydomain.com Connection: keep-alive Cache-Control: max-age=0 Access-Control-Request-Method: GET Origin: http://localhost:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36 Access-Control-Request-Headers: accept, authorization Accept: */* Referer: http://localhost:8000/ Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Response Headers: HTTP/1.1 403 Forbidden Date: Sat, 15 Feb 2014 02:16:05 GMT Content-Type: text/plain; charset=UTF-8 Content-Length: 0 Connection: close 

No estoy del todo seguro de cómo proceder. El filtro Tomcat, por defecto , acepta el encabezado OPTIONS para acceder al recurso.

El problema, creo, es que mi recurso (la URL de solicitud) http://dev.mydomain.com/joeV2/users/listUsers está configurado para aceptar solo los métodos GET:

 @RequestMapping( method=RequestMethod.GET, value="listUsers", produces=MediaType.APPLICATION_JSON_VALUE) @ResponseBody public List list(){ return userService.findAllUsers(); } 

¿Esto significa que debo hacer que ese método / punto final también acepte el método OPTIONS? Si es así, ¿significa eso que debo hacer explícitamente que cada punto final REST acepte el método OPTIONS? Además del código desordenado, estoy confundido de cómo eso funcionaría. Por lo que entiendo, la verificación previa de OPTIONS es para que el navegador valide que el navegador debe tener acceso al recurso especificado. Lo cual entiendo significa que mi método de controlador no debería ser llamado durante la verificación previa. Entonces, especificar OPCIONES como un método aceptado sería contraproducente.

¿Tomcat debería responder a la solicitud OPTIONS directamente sin siquiera acceder a mi código? Si es así, ¿falta algo en mi configuración?

Me senté y depuré a través de org.apache.catalina.filters.CorsFilter para descubrir por qué estaba prohibida la solicitud. Con suerte, esto puede ayudar a alguien en el futuro.

De acuerdo con la sección 6.2 de W3 CORS Spec Preflight Requests , la verificación previa debe rechazar la solicitud si el encabezado enviado no coincide con los encabezados permitidos.

La configuración predeterminada para CorsFilter cors.allowed.headers (como la suya) no incluye el encabezado Authorization que se envía con la solicitud.

cors.allowed.headers configuración de filtro cors.allowed.headers para aceptar el encabezado de authorization y la solicitud de verificación previa ahora es exitosa.

  CorsFilter org.apache.catalina.filters.CorsFilter  cors.allowed.headers Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization   

Por supuesto, no estoy seguro de por qué el encabezado de authorization no está permitido por defecto por el filtro CORS.

Lo primero que trataría de hacer es configurar sus encabezados comunes para sus solicitudes http que distribuye de forma angular, insertando el siguiente bloque de configuración en su módulo:

 .config(function($httpProvider){ $httpProvider.defaults.headers.common = {}; $httpProvider.defaults.headers.post = {}; $httpProvider.defaults.headers.put = {}; $httpProvider.defaults.headers.patch = {}; }) 

Se supone que estos ya están configurados por defecto, pero he descubierto que a menudo tengo que hacer esto manualmente en mi configuración debido a las anulaciones de otros módulos o al proceso interno de bootstraping angular.

Su filtro CORS debe ser suficiente en el lado del servidor para permitir este tipo de solicitudes, pero a veces, necesita especificar métodos de solicitud además de sus orígenes, así como los tipos de contenido aceptados. Los documentos tomcat tienen este bloque avanzado, que se ocupa de esos.

   CorsFilter org.apache.catalina.filters.CorsFilter  cors.allowed.origins *   cors.allowed.methods GET,POST,HEAD,OPTIONS,PUT   cors.allowed.headers Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers   cors.exposed.headers Access-Control-Allow-Origin,Access-Control-Allow-Credentials   cors.support.credentials true   cors.preflight.maxage 10    CorsFilter /*  

Si el primero no funciona por sí solo, intente mejorar sus filtros, especialmente:

  cors.allowed.methods GET,POST,HEAD,OPTIONS,PUT   cors.allowed.headers Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers   cors.exposed.headers Access-Control-Allow-Origin,Access-Control-Allow-Credentials