10

En ASP.NET, FormsAuthenticationModule intercepta cualquier HTTP 401 y devuelve un redireccionamiento HTTP 302 a la página de inicio de sesión. Esto es un problema para AJAX, ya que pide json y obtiene la página de inicio de sesión en html, pero el código de estado es HTTP 200.Prevención de formularios AutenticaciónMódulo de interceptación de respuestas de API Web ASP.NET

¿Cuál es la forma de evitar esta intercepción en ASP.NET Web API?

En ASP.NET MVC4 es muy fácil de prevenir esta intercepción, poniendo fin a la conexión de forma explícita:

public class MyMvcAuthFilter:AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest() && !filterContext.IsChildAction) 
     { 
      filterContext.Result = new HttpStatusCodeResult(401); 
      filterContext.HttpContext.Response.StatusCode = 401; 
      filterContext.HttpContext.Response.SuppressContent = true; 
      filterContext.HttpContext.Response.End(); 
     } 
     else 
      base.HandleUnauthorizedRequest(filterContext); 
    } 
} 

Pero en API Web ASP.NET no puedo finalizar la conexión de forma explícita, por lo que incluso cuando se utiliza este código de la FormsAuthenticationModule intercepta la respuesta y envía un redireccionamiento a la página de inicio de sesión:

public class MyWebApiAuth: AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     if(actionContext.Request.Headers.Any(h=>h.Key.Equals("X-Requested-With",StringComparison.OrdinalIgnoreCase))) 
     { 
      var xhr = actionContext.Request.Headers.Single(h => h.Key.Equals("X-Requested-With", StringComparison.OrdinalIgnoreCase)).Value.First(); 

      if (xhr.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase)) 
      { 
       // this does not work either 
       //throw new HttpResponseException(HttpStatusCode.Unauthorized); 

       actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); 
       return; 
      } 
     } 

     base.HandleUnauthorizedRequest(actionContext); 
    } 
} 

¿Cuál es la forma de evitar este comportamiento en ASP.NET web API? He estado mirando y no he podido encontrar la manera de hacerlo.

Atentamente.

PD: No puedo creer que esto sea en 2012 y este problema aún está activo.

+1

Para cualquier otra persona buscando, intente esto: http://blog.craigtp.co.uk/post/OWIN-Hosted-Web-API-in-an-MVC-Project – Sentinel

+0

El enlace publicado por @Sentinel corrige mi problema ... ¡gracias! –

Respuesta

4

Las notas de la versión para MVC 4 RC implican que esto se ha resuelto desde la versión Beta, ¿qué estás usando?

solicitudes

http://www.asp.net/whitepapers/mvc4-release-notes no autorizadas manejados por ASP.NET Web API de retorno 401 Unauthroized: las solicitudes no autorizadas manejados por API Web ASP.NET ahora devolver una respuesta 401 no autorizado estándar en lugar de redirigir el agente de usuario a un formulario de acceso para que la respuesta puede ser manejado por un cliente Ajax.

buscando en el código fuente para MVC parece ser una funcionalidad añadida a través de SuppressFormsAuthRedirectModule.cs

http://aspnetwebstack.codeplex.com/SourceControl/network/forks/BradWilson/AspNetWebStack/changeset/changes/ae1164a2e339#src%2fSystem.Web.Http.WebHost%2fHttpControllerHandler.cs.

internal static bool GetEnabled(NameValueCollection appSettings) 
    { 
      // anything but "false" will return true, which is the default behavior 

para que se vea este esto está activada por defecto y RC debe resolver el problema sin ningún heroísmo ... como un punto de lado que parece que se puede desactivar este nuevo módulo utilizando AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815:

<appSettings> 
    <Add Key = "webapi:EnableSuppressRedirect" value = "false" /> 
</appSettings> 

Editar (ejemplo y aclaración)

ahora he creado un ejemplo de este enfoque en GitHub. La nueva supresión de redirección requiere que use los dos atributos correctos de "Autorizar"; MVC Web [System.Web.Mvc.Authorize] y Web API [System.Web.Http.Authorize] en los controladores Y/O en los filtros globales Link.

Este ejemplo sin embargo muestra una limitación del enfoque. Parece que los nodos de "autorización" en el web.config siempre tendrán prioridad sobre las rutas MVC, p. config como esto anulará sus reglas y todavía redirigir para iniciar sesión:

<system.web> 
    <authentication mode="Forms"> 
    </authentication> 
    <authorization> 
     <deny users="?"/> //will deny anonymous users to all routes including WebApi 
    </authorization> 
</system.web> 

Lamentablemente abrir esto para algunas rutas URL usando el elemento de ubicación no parecen funcionar y continuará siendo interceptada y redirigida a las llamadas WebAPI iniciar sesión.

Soluciones

Para aplicaciones MVC estoy limitan a sugerir la eliminación de la configuración de Web.Config y quedarse con filtros globales y atributos en el código.

Si debe usar los nodos de autorización en Web.Config para MVC o tiene una aplicación híbrida ASP.NET y WebApi, @PilotBob - en los comentarios a continuación - ha encontrado que las subcarpetas y múltiples Web.Config's se pueden usar para Toma tu pastel y cometelo.

+0

Estoy usando beta porque la semana pasada intenté obtener la versión más reciente, y el DependencyResolver no funcionaba como se esperaba, por lo que Ninject MVC no funcionó, intenté un par de soluciones alternativas por el momento, pero no funcionó . ¿Sabes algo sobre eso? Un millón de gracias. – vtortola

+1

@NullOrEmpty Oh, OK. Estoy en el RC con Ninject (me mudé de Autofac porque tuve problemas en los primeros días del RC). Este enlace describe un enfoque idéntico al mío y debería funcionar bien http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/ –

+0

¡Muchas gracias! Lo probaré más tarde. – vtortola

2

que fue capaz de eludir la configuración de negar el anonimato en web.config mediante el establecimiento de la siguiente propiedad:

Request.RequestContext.HttpContext.SkipAuthorization = true;

Lo hago después de algunas comprobaciones contra el objeto Request en el método Application_BeginRequest en Global.asax.cs, como la propiedad RawURL y otra información de encabezado para asegurarme de que la solicitud está accediendo a un área que deseo permitir acceso anónimo a . Todavía realizo la autenticación/autorización una vez que se llama a la acción API.

5

En caso de que alguien está interesado en tratar con el mismo problema en ASP.NET MVC aplicación utilizando el atributo Autorizar:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
public class Authorize2Attribute : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAuthenticated) 
     { 
      filterContext.Result = new HttpStatusCodeResult((int) HttpStatusCode.Forbidden); 
     } 
     else 
     { 
      if (filterContext.HttpContext.Request.IsAjaxRequest()) 
      { 
       filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 
      } 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
    } 
} 

Este explorador manera distingue correctamente entre las solicitudes autorizadas y prohibidas ..

Cuestiones relacionadas