c# http-headers cors servicestack

c# - ServiceStack, CORS y OPTIONS(sin encabezado Access-Control-Allow-Origin)



http-headers (2)

Estamos teniendo problemas con las funciones CORS de una API relajante en ServiceStack 4.

Queremos analizar las cookies de la API, ya que la sesión de SS está en las cookies, por lo que hacemos AJAX calles con "WithCredentials" = verdadero en nuestros clientes angulares que acceden a la API.

Dado que a Chrome (al menos) no le gustan los comodines de Access-Control-Allow-Origin con WithCredentials, hemos agregado un filtro de solicitud previa para repetir el origen del solicitante en el encabezado Access-Control-Allow-Origin de la siguiente manera:

private void ConfigureCors() { Plugins.Add(new CorsFeature( allowedHeaders: "Content-Type", allowCredentials: true, allowedOrigins: "")); PreRequestFilters.Add((httpReq, httpRes) => { string origin = httpReq.Headers.Get("Origin"); if (origin != null) { httpRes.AddHeader(HttpHeaders.AllowOrigin, origin); } else { // Add the dev localhost header. httpRes.AddHeader(HttpHeaders.AllowOrigin, "http://localhost:9000"); } }); PreRequestFilters.Add((httpReq, httpRes) => { //Handles Request and closes Responses after emitting global HTTP Headers if (httpReq.Verb == "OPTIONS") { httpRes.EndRequest(); } }); }

Sin embargo, estamos llegando a un inconveniente en las solicitudes OPTIONS, porque el servicio SS no está emitiendo el encabezado Access-Control-Allow-Origin cuando la solicitud finaliza. Esto hace que Chrome rechace la llamada.

Intentamos poner un encabezado explícito dentro del filtro de solicitud previa para OPTIONS, pero todavía no devuelve un encabezado ACAO para las llamadas OPTIONS:

PreRequestFilters.Add((httpReq, httpRes) => { //Handles Request and closes Responses after emitting global HTTP Headers if (httpReq.Verb == "OPTIONS") { httpRes.AddHeader(HttpHeaders.AllowOrigin, "*"); httpRes.EndRequest(); } });

Parece que esto debe haber sido tratado anteriormente, pero no pudimos encontrar nada como esto en StackOverflow.

¿Estamos haciendo algo mal con el filtro de solicitud previa OPTIONS? ¿Por qué no devuelve un encabezado Access-Control-Allow-Origin?


Debería agregar los dominios incluidos en la lista blanca en la allowOriginWhitelist , por ejemplo:

Plugins.Add(new CorsFeature(allowedHeaders:"Content-Type", allowCredentials:true, allowOriginWhitelist:new[]{"http://localhost:9000"}));

Se presentó un problema en v4.0.35 donde, como PreRequestFilters se escribían en Custom HttpHandlers, esto hizo que CorsFeature escribiera dos veces el encabezado Access-Control-Allow-Origin, lo que hacía que los navegadores lo rechazaran. Esto ahora se ha resuelto en este compromiso, que está disponible desde v4.0.36 + que ahora está disponible en MyGet .

Esta última versión se ha implementado en la demostración http://test.servicestack.net que muestra la autenticación entre dominios con ServiceStack en este jsbin: http://jsbin.com/korijigucu/1/edit

<!DOCTYPE html> <html ng-app="app"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script> <meta charset="utf-8"> <title>JS Bin</title> <script> var apiBase = "http://test.servicestack.net"; var app = angular.module(''app'', []); app.run([''$rootScope'', ''$http'', function ($rootScope, $http) { $rootScope.success = "running..."; $http .post(apiBase + ''/auth/credentials'', { "UserName": "test", "Password": "test" }, { withCredentials: true }) .success(function (data) { $rootScope.success = "Login successful: " + JSON.stringify(data); }) .error(function (data, status, headers, config) { $rootScope.error = ''ERR:login''; }); }]); </script> </head> <body> <div style=''color:green''>{{success}}</div> <div style=''color:red''>{{error}}</div> </body> </html>

Código fuente para el registro de CorsFeature en el proyecto de prueba anterior :

Plugins.Add(new CorsFeature( allowOriginWhitelist: new[] { "http://localhost", "http://localhost:56500", "http://test.servicestack.net", "http://null.jsbin.com" }, allowCredentials: true, allowedHeaders: "Content-Type, Allow, Authorization"));


Nota: La actualización a 4.0.36 resolvió el problema del doble encabezado que se describe a continuación, lo que hace que el segundo filtro de solicitud previa sea obsoleto.

Finalmente conseguí que esto funcionara, pero se siente como un obstáculo.

Agregué la entrada allowOriginWhitelist como sugirió Demis, que devolvía los valores duplicados para el encabezado ( Access-Control-Allow-Origin:http://localhost:9000 ), al menos para las llamadas OPTIONS (parece funcionar bien para POST y GET )

Plugins.Add(new CorsFeature( allowedHeaders: "Content-Type, Allow, Authorization", allowCredentials: true, allowOriginWhitelist: new[] { "http://localhost:9000", "http://www.productiondomain.com", "https://www.productiondomain.com" }));

Así que agregué el siguiente filtro de solicitud previa, basado en el filtro anterior que estábamos usando:

PreRequestFilters.Add((httpReq, httpRes) => { //Handles Request and closes Responses after emitting global HTTP Headers if (httpReq.Verb == "OPTIONS") { string origin = httpReq.Headers.Get("Origin"); if (origin != null) { httpRes.AddHeader(HttpHeaders.AllowOrigin, origin); } else { // Add the dev localhost header. httpRes.AddHeader(HttpHeaders.AllowOrigin, "http://localhost:9000"); } httpRes.EndRequest(); } });

Esto ha resuelto el problema, pero se siente como un obstáculo. ¿Alguien sabe por qué este código simple produciría doble encabezados de ACAO en la respuesta?

Plugins.Add(new CorsFeature( allowedHeaders: "Content-Type, Allow, Authorization", allowCredentials: true, allowOriginWhitelist: new[] { "http://localhost:9000", "http://www.productiondomain.com", "https://www.productiondomain.com" }));