Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpStatusCodeResult(401) returns “200 OK”

Using ASP.NET MVC 5, I would like to return appropriate HTTP status code for different scenarios (401 for user is not authenticated, 403 when user has no right for some resource, etc.), then handle them in jQuery.

But the problem is, when I try to return 401, it always returns "200: OK". MVC 5 RC1 was giving "302: Found" instead of 401, so I could use a workaround (HttpStatusCodeResult(401) returns "302 Found"). But now I moved from MVC 5 RC1 to MVC 5 and this behaviour changed. Now it is always "200: OK". So my workaround is useless, of course I can't replace 200 with anything else.

public ActionResult My()
{
    if (User.Identity.IsAuthenticated == false)
    {
        return new HttpStatusCodeResult(401, "User is not authenticated."); 
            // Returns "200: OK"
    }

   // ... other code ...
}

How to solve this?

like image 215
Adam Szabo Avatar asked Nov 17 '13 18:11

Adam Szabo


1 Answers

The MVC 5+ Pipeline modifies 401 response codes.

Option 1 With .net 4.5

you can set HttpContext.Response.SuppressFormsAuthenticationRedirect to true.

e.g. in your custom AuthoriseAttribute.cs

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new JsonResult
            {
                Data = "_Logon_",
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
        }

Option 2. If not using .net 4.5

  public class SuppressFormsAuthenticationRedirectModule : IHttpModule
{
    private static readonly object SuppressAuthenticationKey = new object();

    public static void Register()
    {
        DynamicModuleUtility.RegisterModule(
            typeof(SuppressFormsAuthenticationRedirectModule));
    }

    public static void SuppressAuthenticationRedirect(HttpContext context)
    {
        context.Items[SuppressAuthenticationKey] = true;
    }

    public static void SuppressAuthenticationRedirect(HttpContextBase context)
    {
        context.Items[SuppressAuthenticationKey] = true;
    }

    public void Init(HttpApplication context)
    {
        context.PostReleaseRequestState += OnPostReleaseRequestState;
        context.EndRequest += OnEndRequest;
    }

    public void Dispose()
    {
    }

    private void OnPostReleaseRequestState(object source, EventArgs args)
    {
        var context = (HttpApplication)source;
        var response = context.Response;
        var request = context.Request;

        if (response.StatusCode == 401 && request.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            SuppressAuthenticationRedirect(context.Context);
        }
    }

    private void OnEndRequest(object source, EventArgs args)
    {
        var context = (HttpApplication)source;
        var response = context.Response;

        if (context.Context.Items.Contains(SuppressAuthenticationKey))
        {
            response.TrySkipIisCustomErrors = true;
            response.ClearContent();
            response.StatusCode = 401;
            response.RedirectLocation = null;
        }
    }
}

and in web.config

 <modules>
  <add name="SuppressFormsAuthenticationRedirectModule" type="SuppressFormsAuthenticationRedirectModule"/>
</modules>

See here for more info

like image 144
Damian Green Avatar answered Oct 06 '22 20:10

Damian Green