tags:

views:

1829

answers:

4

How to disable standard ASP.NET handling of 401 response code (redirecting to login page) for AJAX/JSON requests?

For web-pages it's okay, but for AJAX I need to get right 401 error code instead of good looking 302/200 for login page.

A: 

You could choose to create a custom FilterAttribute implementing the IAuthorizationFilter interface.

In this attribute you add logic to determine if the request are supposed to return JSON. If so, you can return an empty JSON result (or do whatever you like) given the user isn't signed in. For other responses you would just redirect the user as always.

Even better, you could just override the OnAuthorization of the AuthorizeAttribute class so you don't have to reinvent the wheel. Add the logic I mentioned above and intercept if the filterContext.Cancel is true (the filterContext.Result will be set to an instance of the HttpUnauthorizedResult class.

Read more about "Filters in ASP.NET MVC CodePlex Preview 4" on Phil Haacks blog. It also applies to the latest preview.

troethom
But I still can't get 401 Response status code for AJAX request.Even if I set up response in Autorization filter. Since ASP.NET infrastructure that catch 401 response and redirecting to login page sits over ASP.NET MVC. Letting know that user is not logged by empty JSON result is not very right...
derigel
I didn't understand exactly what you had in mind until now. I am adding a new answer that will solve your problem.
troethom
+4  A: 

The ASP.NET runtime is developed so that it always will redirect the user if the HttpResponse.StatusCode is set to 401, but only if the <authentication /> section of the Web.config is found.

Removing the authentication section will require you to implement the redirection to the login page in your attribute, but this shouldn't be a big deal.

troethom
The best way to implement your own redirection is to subclass AuthorizeAttribute, and when not authorized set the result to a RedirectResult instead of HttpUnauthorizedResult.
Joseph Daigle
Yes, but in this case the OP would like to send HTTP code 401, but not redirecting (to work properly with JSON).
troethom
A: 

You could also use the Global.asax to interrupt this process with something like this:

    protected void Application_PreSendRequestHeaders(object sender, EventArgs e) {
     if (Response.StatusCode == 401) {
      Response.Clear();
      Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx"));
      return;
     }
    }
Jared
I did this, except I checked for the 302 and X-Requested-With in the answer from @troethom above.
Marc
+2  A: 

In classic ASP.NET you get a 401 http response code when calling a WebMethod with Ajax. I hope they'll change it in future versions of ASP.NET MVC. Right now I'm using this hack:

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
    {
        Context.Response.Clear();
        Context.Response.StatusCode = 401;
    }
}
Catalin DICU
This is a really good stop-gap solution if you need something fast that works. Otherwise I'd would try to implement @troethom answer.
Joseph Daigle