2012-05-23 14 views
28

Estoy intentando habilitar el soporte CORS en mi proyecto WebAPI, y si habilito la autenticación anónima, todo funciona bien, pero con la autenticación anónima Windows Auth + deshabilitada, la solicitud OPTIONS enviado siempre devuelve una respuesta 401 no autorizada. El sitio que lo solicita está en el DOMINIO, por lo que debería poder realizar la llamada, ¿hay alguna forma de evitar el problema sin desactivar la Autenticación de Windows?401 respuesta para solicitud CORS en IIS con autorización de Windows habilitada

+0

¿Ha comprobado si la autenticación integrada de Windows es realmente compatible con su máquina? [http://technet.microsoft.com/en-us/library/cc754628%28v=WS.10%29.aspx](http://technet.microsoft.com/en-us/library/cc754628%28v= WS.10% 29.aspx) –

+0

Sí, ejecutándose en W7 Ultimate y también en Server 2008. Pegaré en una respuesta que recibí de MS, parece posible, simplemente no es fácil de ninguna manera, vamos a cambiar a un estilo más oauth en su lugar y separar nuestra API para permitir la autenticación anónima, pero emitir tokens para la autorización. – dariusriggins

Respuesta

11

Desde MS:

Si deshabilita la autenticación anónima, es por diseño que IIS devolverá un 401 a cualquier petición. Si han habilitado la autenticación de Windows, la respuesta 401 en ese caso tendría un encabezado WWW-Authenticate para permitir que el cliente inicie un protocolo de autenticación. La pregunta entonces es si el cliente que el cliente está utilizando puede hacer la autenticación de Windows o no.

Por último, parece que podría haber una cuestión de fondo sobre si es posible o no para configurar un enlace que se permite el acceso anónimo para un verbo (OPCIONES, en este caso), sino que requieren la autenticación de Windows para otros verbos. IIS no es compatible con esto a través de una configuración simple. Es posible obtener este comportamiento habilitando tanto la autenticación anónima como la de Windows, estableciendo ACL en el contenido que niega el acceso al usuario anónimo y luego configurando la asignación del controlador para la URL en cuestión para que no verifique la existencia del archivo asociado con la URL. Pero tomaría algo de juego con esto para confirmar esto.

+2

Acabo de notar que muchos chicos han experimentado los errores 401 cuando su API web está protegida por la autenticación de Windows o tal. Las solicitudes de verificación previa de CORS no contienen credenciales, por lo que IIS responderá con 401.2 incluso antes de que ASP.NET las toque. Una solución sucia es escribir un módulo HTTP y engancharlo a IIS Pipeline, que se registra en el evento 'HttpApplication.BeginRequest' donde este módulo devuelve la respuesta 200 esperada para las solicitudes de verificación previa. Esta solución alternativa solo se aplica al modo integrado IIS 7+. Lamentablemente, el soporte de Microsoft puede no ser consciente de este consejo. –

+1

Acabo de publicar un blog, https://blog.lextudio.com/2014/11/how-to-handle-cors-preflight-requests-in-asp-net-mvcweb-api-with-windows-authentication/ with más información sobre IIS 6 y usuarios de modo clásico. –

+0

@LexLi lee tu blog, pero desafortunadamente no detallas la implementación exacta del evento BeginRequest, por lo que no tengo claro qué incluir en la respuesta 200 (por ejemplo, encabezados, etc.). Entiendo cómo construir HttpModules, solo me gustaría aclarar qué responder a la solicitud de verificación previa. –

3

He tenido el mismo problema hoy debido a un error en IE 10 and 11, estoy usando ServiceStack en lugar de WebApi, pero el enfoque también puede funcionar para usted.

  1. Habilitado la autenticación integrada y anónima de Windows en el sitio web de IIS.
  2. tienen una serie de filtros en la tubería ServiceStack,
    • Para el manejo de petición Cors y opciones, disponible bajo petición, agrego cabeceras necesarias y poner fin a la petición,
    • filtro para comprobar includng HttpRequest se autentica ?,
    • etc filtro,

Después de pasar por todos los filtros, se ejecuta el servicio.

CorsFeature.cs

AuthenticateFilter

En mi apphost,

appHost.Plugins.Add(new CorsFeature()); 

appHost.RequestFilters.Add(AuthenticateFilter.Authenticate); 

que han modificado el CorsFeature de manejar de OptionsRequest, además de la adición de cabeceras, Autenticación del filtro para comprobar si hay solicitudes autenticadas!

+0

Hola, ¿puedes dar un poco más de detalles sobre lo que hiciste? Me enfrento a problemas similares y también estoy usando ServiceStack que se implementa a través de SharePoint 2013 – link64

+1

Estoy haciendo una comprobación de omisión de Es el usuario autenticado para las solicitudes de OPCIONES. Agregaré un ejemplo de código. –

33

Puede permitir solo el verbo OPTIONS para usuarios anónimos.

<system.web> 
    <authentication mode="Windows" /> 
    <authorization> 
     <allow verbs="OPTIONS" users="*"/> 
     <deny users="?" /> 
    </authorization> 
</system.web> 

Según las especificaciones del W3C, navegador excluye las credenciales de usuario de CORS verificación previa: https://dvcs.w3.org/hg/cors/raw-file/tip/Overview.html#preflight-request

+1

¿Requiere esto habilitar el módulo de autenticación anónima en IIS? – UserControl

+6

Aparentemente sí. "La autenticación anónima les brinda a los usuarios acceso a las áreas públicas de su sitio web o FTP sin pedirles un nombre de usuario o contraseña". http://bit.ly/1wjLdO9 –

+2

Esta debería ser la respuesta aceptada. – slashp

13

Varios años más tarde, pero a través de la respuesta de @dariusriggins y @ lex-li he conseguido añadir el siguiente código a mi Global.asax:

public void Application_BeginRequest(object sender, EventArgs e) 
    { 
     string httpOrigin = Request.Params["HTTP_ORIGIN"]; 
     if (httpOrigin == null) httpOrigin = "*"; 
     HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", httpOrigin); 
     HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 
     HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Token"); 
     HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true"); 

     if (Request.HttpMethod == "OPTIONS") 
     { 
      HttpContext.Current.Response.StatusCode = 200; 
      var httpApplication = sender as HttpApplication; 
      httpApplication.CompleteRequest(); 
     } 
    } 

la httpOrigin es en realidad se veía en una lista de hosts permitidos pero que las cosas complicadas. Esto significa que todas las demás solicitudes se validan pero las opciones simplemente vuelven.

Gracias por esta pregunta, me habría perdido sin ella!

+1

He intentado muchas maneras diferentes de habilitar CORS con WebAPI que se ejecuta en IIS para un cliente de Angular 2, incluido agregarlo a web.config, anotaciones de datos en mis acciones de controlador y llamar a 'EnableCors' en WebApiConfig.Register. Esta solución es la ** única ** que realmente funcionó con la Autenticación de Windows (NTLM), junto con asegurarse de que el cliente http Angular 2 estaba enviando 'withCredentials' en el encabezado HTTP. ¡Gracias! –

+0

¡Esto es brillante! ¡Funciona de maravilla! Ni siquiera tiene que ponerlo en Application_BeginRequest. Incluso puede ponerlo en la carga de su página si es solo una página que desea permitir. – Shiroy

0

Lo que funcionó para mí (cuando se trabaja con AngularJS o jQuery) es añadir withCredentials: true a cada solicitud de cliente:

$http.get("http://localhost:88/api/tests", {withCredentials :true}) 

y permitiendo CORS en el servidor, esto se hizo con Microsoft.Owin.Cors de Nuget y añadiéndola en Puesta en marcha, como a continuación:

public void Configuration(IAppBuilder app) 
    { 
     HttpConfiguration config = new HttpConfiguration(); 

     ConfigureOAuth(app); 

     WebApiConfig.Register(config); 
     app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); 
     app.UseWebApi(config); 

    } 

Referencias:

4

La forma más fácil de solucionar este problema es crear una regla de reescritura con la condición REQUEST_METHOD =^$ OPCIONES. Luego configure la acción como una respuesta personalizada, ajústela a 200 OK. Entonces, todas las solicitudes de opciones responderán con 200 en lugar de 401. Esto solucionará el problema CORS.

Por supuesto, aún necesita asegurarse de tener los encabezados de solicitud de origen cruzados correctos.

Esto detendrá las solicitudes de opciones (que no tienen credenciales) respondiendo con 401 cuando la autenticación integrada está habilitada.

+0

¿Ve algún problema potencial de seguridad con esto? –

1

La respuesta aceptada es correcta; sin embargo, durante un tiempo solucioné problemas en una API de reposo con una configuración de "nodo con iisnodo y npm cors" y no me sentía cómoda con la autenticación anónima para todos los usuarios. Como es una aplicación de nodo, la etiqueta system.web no hace mucho. Terminé con la siguiente adición al web.config:

<system.webServer> 
<security> 
    <requestFiltering> 
    <hiddenSegments> 
     <add segment="node_modules" /> 
    </hiddenSegments> 
    </requestFiltering> 
    <authorization> 
    <add accessType="Allow" verbs="OPTIONS" users="?" /> 
    <add accessType="Deny" verbs="GET, PUT, POST, DELETE" users="?" /> 
    </authorization> 
</security> 
</system.webServer> 
0

Activación SupportCredentials en EnableCorsAttribute en WebApiConfig.cs hizo el truco para mí:

public static void Register(HttpConfiguration config) 
{   
    //enable cors request just from localhost:15136 
    var cors = new EnableCorsAttribute("http://localhost:15136", "*", "*"); 
    cors.SupportsCredentials = true; 
    config.EnableCors(cors); 

    //other stuff 
} 

https://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Asegúrese de que envíe credenciales cuando se llama desde JavaScript ({withCredentials :true})

+0

Estoy intentando lo mismo pero sin credenciales. Sin suerte, incluso con autorización anónima – jpfreire

0

estoy usando API web y OWIN y probado todas sugerido hasta lución pero el único que funcionó fue el siguiente

//use it in your startup class 
app.Use((context, next) => 
{ 
    if (context.Request.Headers.Any(k => k.Key.Contains("Origin")) && context.Request.Method == "OPTIONS") 
    { 
     context.Response.StatusCode = 200; 
     context.Response.Headers.Add("Access-Control-Allow-Origin", new string[1] { "ALLOWED_ORIGIN" }); 
     context.Response.Headers.Add("Access-Control-Allow-Headers", new string[4] { "Origin", "X-Requested-With", "Content-Type", "Accept" }); 
     context.Response.Headers.Add("Access-Control-Allow-Methods", new string[5] { "GET", "POST", "PUT", "DELETE", "OPTIONS" }); 
     context.Response.Headers.Add("Access-Control-Allow-Credentials", new string[1] { "true" }); 

     return context.Response.WriteAsync(""); 
    } 

    return next.Invoke(); 
}); 

//this is important! Without it, it didn't work (probably because the middleware was too late) 
app.UseStageMarker(PipelineStage.Authenticate); 

es necesario insertar el código en algún lugar en una de sus clases de inicio OWIN. Es importante llamar al app.UseStageMarker(PipelineStage.Authenticate) porque, de lo contrario, falla la verificación de verificación previa. Más información para UseStageMarker ->https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline

También es importante que necesite definir explícitamente los encabezados permitidos. Fallará si usa * como marcador de posición.

Quizás ayuda a alguien.

Cuestiones relacionadas