Reputation: 1231
In building a content management system that incorporates jquery ajax into it's GUI I have come across a hurdle. It seems that some customers spend too long thinking about what they are going to write and therefore the server session logs them out, naturally being the web they have no idea about this. When they attempt to submit the changes I use an ajax call to the server to save the data.
What I would expect to happen next is that the MVC server application would return a "401 Unauthorized" status. I could then get my jquery ajax object to ask the user to login and then resend changes once the user was authorized.
However, what is actually returned from the MVC application is a "302 Found" status and a redirect URL to my login form page. The login form page returns a "200 OK" status code and the jquery ajax object calls the success event that tells the user everything was successful because thats what the MVC application is saying.
Is there a way for me to get the MVC application to play the way I think it should or do I have to modify my jquery ajax events to detect the login page?
Update:
I've used reflector to have a look in the MVC code and the authorize attribute, return a NotAuthorizedResult the code for that is below (0x191 = 401)
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.HttpContext.Response.StatusCode = 0x191;
}
I'm thinking that maybe the Forms Authorization HttpModule is seeing the 401 and forcing the redirect.
Upvotes: 4
Views: 5112
Reputation: 11
I've found that a more lightweight approach is simply to add a custom HTTP header to the login page and then check for the presence of that in the AJAX success callback.
Ie. in the LoginController (this is an MVC project, but the same principle should apply for other ASP.NET solutions):
public ActionResult Login(string returnUrl = "")
{
Response.AddHeader("X-Unauthorized", "true");
...
And then in the client-side AJAX handler:
success: function(data, textStatus, jqXhr)
{
if (jqXhr.getResponseHeader("X-Unauthorized"))
{
...
This works for me at least.
Upvotes: 1
Reputation:
I really like this solution. By changing the 302 response on ajax requests to a 401 it allows you to setup your ajax on the client side to monitor any ajax request looking for a 401 and if it finds one to redirect to the login page. Very simple and effective.
Global.asax:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 &&
Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
Context.Response.Clear();
Context.Response.StatusCode = 401;
}
}
Client Side Code:
$(function () {
$.ajaxSetup({
statusCode: {
401: function () {
location.href = '/Logon.aspx?ReturnUrl=' + location.pathname;
}
}
});
});
Upvotes: 4
Reputation: 1921
you could try something like this:
void context_EndRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication;
var response = app.Response;
var request = app.Request;
if ((response.StatusCode == 302) && IsAjaxRequest(request))
response.StatusCode = 401;
}
in a HttpModule, it will be after the FormsAuth module in sequence so will correct the status code. Not pretty but effective.
Upvotes: 6