Prevent FormsAuthenticationModule of intercepting ASP.NET Web API responses

vtortola picture vtortola · Jun 18, 2012 · Viewed 7.7k times · Source

In ASP.NET the FormsAuthenticationModule intercepts any HTTP 401, and returns an HTTP 302 redirection to the login page. This is a pain for AJAX, since you ask for json and get the login page in html, but the status code is HTTP 200.

What is the way of avoid this interception in ASP.NET Web API ?

In ASP.NET MVC4 it is very easy to prevent this interception by ending explicitly the connection:

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);
    }
}

But in ASP.NET Web API I cannot end the connection explicitly, so even when I use this code the FormsAuthenticationModule intercepts the response and sends a redirection to the login page:

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);
    }
}

What is the way of avoiding this behaviour in ASP.NET Web API? I have been taking a look, and I could not find a way of do it.

Regards.

PS: I cannot believe that this is 2012 and this issue is still on.

Answer

Ostati picture Ostati · Jul 6, 2013

In case someone's interested in dealing with the same issue in ASP.NET MVC app using the Authorize attribute:

[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);
        }
    }
} 

This way browser properly distinguishes between Forbidden and Unauthorized requests..