Unauthorized result in ajax requests
Asked Answered
U

4

20

I have application with many ajax actions (implemented using JQuery.ajax), that returns JSON ot html. Some of them should be accessible only to authorized users, and I decorated them with [Authorize] attribute. For not ajax actions, if user not authorized - system redirects him to login page (that configured in web.config).

But this is not applicable for ajax actions, because if user was authorized - he load page, after that cookie expires and he is not authorized, and instead of html block, that should replace old, he get my login page inside block.

I know that I can solve this problem manually, for example remove [Authorize] attribute, and return special json/empty html, if user no authorized. But I dislike this solution, because I need to rewrite all my actions and ajax functions. I want global solution, that allow me not to rewrite my actions (may be custom authorize attribute, or some http unauthorized result custom handling).

I want to return status code, if request is ajax, and redirect to login page, if request isn't ajax.

Uveitis answered 7/3, 2012 at 20:57 Comment(3)
"I want to return status code, if request is ajax, and redirect to login page, if request isn't ajax." -- seems liked you already outlined the solution to this problem, no?Exhaustless
What have you tried to do at this point? There is going to be some rewriting involved no matter what route you take.Pastrami
Sometimes I'm an idiot. Try using Request.isAjaxRequest();Cassella
B
32

Add an Application_EndRequest handler to your code in global.asax.cs that modifies any 302 error (redirect to login page) to an 401 (unauthorized) error for an AJAX request. This will allow you to simply leave your controller actions as they are and handle the redirect (you really can only have the user login again if they aren't currently) via the client.

protected void Application_EndRequest()
{
    // Any AJAX request that ends in a redirect should get mapped to an unauthorized request
    // since it should only happen when the request is not authorized and gets automatically
    // redirected to the login page.
    var context = new HttpContextWrapper( Context );
    if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
    {
        context.Response.Clear();
        Context.Response.StatusCode = 401;
    }
}

Then in your _Layout.cshtml file add a global AJAX error handler that redirects to your login action when it gets a 401 response.

<script type="text/javascript">
    $(function () {
        $(document).ajaxError(function (e, xhr, settings) {
            if (xhr.status == 401) {
                location = '@Url.Action( "login", "account" )';
            }
        });
    });
</script>

You might also want to try some of the techniques outlined in Phil Haack's blog, Prevent Forms Authentication Login Page Redirect When You Don’t Want It

Burbot answered 7/3, 2012 at 21:9 Comment(1)
if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest() && context.Response.RedirectLocation.StartsWith("/Account/Login")) I suggest adding the RedirectLocation in the condition, or else it might catch some other redirections and return unauthorized... which would not be desired..Handle
A
1

You don't have to rewrite all your actions, just create a custom filter to replace the builtin Authorize filter.

Other people have done it before

asp.net mvc [handleerror] [authorize] with JsonResult?

Appoggiatura answered 7/3, 2012 at 21:2 Comment(0)
R
0

You can check for the Request.IsAjaxRequest() extension method and take specific action if it is true.

Racy answered 7/3, 2012 at 21:4 Comment(0)
G
0

Maybe your LogOn action in your AccountController (or wherever you have it) could return a different result if Request.IsAjaxRequest() was true.

This means that if an AJAX call to an authorised action fails authorisation, you should be able to return an appropriate response via the LogOn action..

e.g.

public ActionResult LogOn()
{
    if (Request.IsAjaxRequest())
    {
        // do appropriate response for ajax call here
    }

    return View();
}

Then, you shouldn't need to do a major rewrite

Gitagitel answered 7/3, 2012 at 21:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.