Confuso su come gestire le richieste di preflight di CORS OPTIONS

Sono nuovo a lavorare con Cross Origin Resource Sharing e sto cercando di ottenere la mia webapp per rispondere alle richieste CORS. La mia webapp è un’app di Spring 3.2 in esecuzione su Tomcat 7.0.42.

Nel web.xml della mia webapp, ho abilitato il filtro CORS di Tomcat:

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

Il mio client (scritto con AngularJS 1.2.12) sta tentando di accedere a un endpoint REST con l’autenticazione di base abilitata. Quando effettua la richiesta GET, Chrome esegue prima il preflight della richiesta, ma riceve una risposta Proibita 403 dal server:

 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 

Non sono del tutto sicuro su come procedere. Il filtro Tomcat, per impostazione predefinita , accetta l’intestazione OPTIONS per accedere alla risorsa.

Il problema, credo, è che la mia risorsa (l’URL della richiesta) http://dev.mydomain.com/joeV2/users/listUsers è configurata per accettare solo i metodi GET:

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

Questo significa che devo fare in modo che quel metodo / punto finale accetti anche il metodo OPTIONS? In tal caso, significa che devo rendere esplicitamente ogni endpoint REST accettare il metodo OPTIONS? A parte il codice ingombrante, sono confuso su come funzionerebbe. Da quello che ho capito, il preflight OPTIONS è che il browser convalidi che il browser debba avere accesso alla risorsa specificata. Che intendo significare che il mio metodo di controllo non dovrebbe nemmeno essere chiamato durante il preflight. Quindi specificare OPZIONI come metodo accettato sarebbe controproducente.

Tomcat dovrebbe rispondere direttamente alla richiesta OPTIONS senza nemmeno accedere al mio codice? Se sì, c’è qualcosa che manca nella mia configurazione?

Mi sono seduto e ho effettuato il debugging attraverso org.apache.catalina.filters.CorsFilter per capire perché la richiesta era vietata. Speriamo che questo possa aiutare qualcuno in futuro.

In base alle specifiche 6.2 Specifiche Preflight W3 CORS Spec , il preflight deve respingere la richiesta se un’intestazione inviata non corrisponde alle intestazioni consentite.

La configurazione di default per CorsFilter cors.allowed.headers (come la tua) non include l’intestazione Authorization che viene inviata con la richiesta.

Ho aggiornato l’impostazione del filtro cors.allowed.headers per accettare l’intestazione authorization e la richiesta di verifica preliminare ora ha esito positivo.

  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   

Naturalmente, non sono sicuro del motivo per cui l’intestazione di authorization non è consentita per impostazione predefinita dal filtro CORS.

La prima cosa che vorrei provare è impostare le intestazioni comuni per le tue richieste http con dispacci angolari, inserendo il seguente blocco di configurazione sul tuo modulo:

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

Questi dovrebbero essere già impostati di default, ma ho scoperto che spesso devo farlo manualmente nella mia configurazione a causa di eventuali sostituzioni da altri moduli o processo di bootstrap angular interno.

Il filtro CORS dovrebbe essere sufficiente sul lato server per consentire questo tipo di richieste, ma a volte è necessario specificare i metodi di richiesta oltre alle origini e ai tipi di contenuto accettati. I documenti tomcat hanno questo blocco avanzato, che li indirizza.

   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 il primo non funziona da solo, prova a migliorare i filtri, in particolare:

  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