Confuso sobre como lidar com solicitações de preflight CORS OPTIONS

Eu sou novo em trabalhar com Cross Origin Resource Sharing e tentar fazer com que meu webapp responda a solicitações de CORS. Meu webapp é um aplicativo do Spring 3.2 em execução no Tomcat 7.0.42.

No web.xml do meu webapp, ativei o filtro CORS do Tomcat:

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

Meu cliente (escrito com o AngularJS 1.2.12) está tentando acessar um terminal REST com a autenticação básica ativada. Quando ele faz sua solicitação GET, o Google Chrome faz o primeiro preenchimento da solicitação, mas está recebendo uma resposta 403 Proibida do 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 

Não sei bem como proceder. O filtro do Tomcat, por padrão , aceita o header OPTIONS para acessar o recurso.

O problema, acredito, é que meu recurso (o URL de solicitação) http://dev.mydomain.com/joeV2/users/listUsers está configurado para aceitar somente os methods GET:

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

Isso significa que devo fazer com que o método / endpoint aceite o método OPTIONS também? Em caso afirmativo, isso significa que tenho que fazer explicitamente cada ponto de extremidade REST aceitar o método OPTIONS? Além do código bagunçado, estou confuso sobre como isso funcionaria. Pelo que entendi a pré-verificação OPTIONS é para o navegador para validar que o navegador deve ter access ao recurso especificado. O que eu entendo significa que o meu método controlador não deve ser chamado durante a pré-impressão. Portanto, especificar OPTIONS como um método aceito seria contraproducente.

O Tomcat deve estar respondendo diretamente à solicitação OPTIONS, mesmo sem acessar meu código? Em caso afirmativo, há algo faltando na minha configuração?

Eu me sentei e depurei através do org.apache.catalina.filters.CorsFilter para descobrir por que o pedido estava sendo proibido. Espero que isso possa ajudar alguém no futuro.

De acordo com a Seção 6.2 Especificação de Solicitações de Pré-impressão do W3 CORS Spec , a pré-impressão deve rejeitar a solicitação se qualquer header enviado não corresponder aos headers permitidos.

A configuração padrão para o CorsFilter cors.allowed.headers (como é seu) não inclui o header de Authorization enviado com a solicitação.

Atualizei a configuração do filtro cors.allowed.headers para aceitar o header de authorization e a solicitação de comprovação agora é bem-sucedida.

  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   

Claro, não sei por que o header de authorization não é permitido por padrão pelo filtro CORS.

A primeira coisa que eu tentaria é configurar seus headers comuns para seus pedidos de HTTP, que são os despachos angulares, inserindo o seguinte bloco de configuração em seu módulo:

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

Estes devem ser definidos por padrão já, mas eu descobri que muitas vezes tenho que fazer isso manualmente na minha configuração devido a qualquer substituição de outros módulos ou processo de bootstrap angular interno.

Seu filtro CORS deve ser suficiente no lado do servidor para permitir esses tipos de solicitações, mas, às vezes, é necessário especificar methods de solicitação além de suas origens, bem como tipos de conteúdo aceitos. Os documentos do tomcat têm esse bloco avançado, que trata disso.

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

Se o primeiro não funcionar por conta própria, tente aprimorar seus 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