35

I have used jquery ajax function to submit a form. The users have to be logged in else they must redirect to a login page.I have used Authorize() attribute for it.

[Authorize]
public ActionResult Creat()
{
....
}

If the user is not login the action return login page to jquery's ajax functions and it is displayed on the same page but I want to redirect the user to login page. Is there any solution?

4 Answers 4

91

Working example: https://github.com/ronnieoverby/mvc-ajax-auth

Important parts:

AjaxAuthorizeAttribute:

using System.Web.Mvc;

namespace MvcApplication1
{
    public class AjaxAuthorizeAttribute : AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(AuthorizationContext context)
        {
            if (context.HttpContext.Request.IsAjaxRequest())
            {
                var urlHelper = new UrlHelper(context.RequestContext);
                context.HttpContext.Response.StatusCode = 403;
                context.Result = new JsonResult
                {
                    Data = new
                    {
                        Error = "NotAuthorized",
                        LogOnUrl = urlHelper.Action("LogOn", "Account")
                    },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
            }
            else
            {
                base.HandleUnauthorizedRequest(context);
            }
        }
    }
}

Javascript:

    $(function () {
        $(document).ajaxError(function (e, xhr) {
            if (xhr.status == 403) {
                var response = $.parseJSON(xhr.responseText);
                window.location = response.LogOnUrl;
            }
        });
    });

Use the attribute in a controller:

    [AjaxAuthorize]
    public ActionResult Secret()
    {
        return PartialView();
    }

Do some ajax:

@Ajax.ActionLink("Get Secret", "Secret", new AjaxOptions { UpdateTargetId = "secretArea", })

<div id="secretArea"></div>
Sign up to request clarification or add additional context in comments.

8 Comments

Totally awesome Ronnie! I love it when a solution just works! Ghooti needs to mark this answer...
I was using formsauthentication redirect and had to enter this line of code to prevent the redirect and the correct http status to be returned... filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
Will the [AjaxAuthorize] attribute on the action override an [Authorize] attribute on the whole controller?
@Odys: No, this will NOT work with a 401 status code. The ASP.net pipeline interferes with 401 before this kicks in. Stick with 403.
@DeepakMurali Well, damn. Where I come from 200's are a good thing.
|
7

Just a handy addition to #Ronnie's answer

if you want to keep the page url on redirect.

 var pathname = window.location.pathname;
        if (xhr.status == 403) {
                var response = $.parseJSON(xhr.responseText);
                window.location = response.LogOnUrl + '?ReturnUrl=' + pathname;
            }

1 Comment

Easier solution imo: returnUrl = context.HttpContext.Request.UrlReferrer.LocalPath for routeValues of urlHelper.Action
0

As another extension to Ronnie Overby's answer.

His solution doesn't work with webapi, but this is fine because you can use normal Authorize attribute instead and then handle the 401 status in the ajaxError function as follows.

    $(document).ajaxError(function (e, xhr) {
    //ajax error event handler that looks for either a 401 (regular authorized) or 403 (AjaxAuthorized custom actionfilter). 
    if (xhr.status == 403 ||xhr.status == 401) {
       //code here
    }
});

Comments

0

If you will observe in the network tab, you will see that the despite the status code being a 200, the server responds with X-Responded-JSON which can be parsed to get the actual server status code response which is 401 in this case so you can handle the response from the Authorize attribute in your AJAX call like this in your .cshtml View file:

$.ajax({
    url: '@Url.Action("MyMethod", "MyController")',
    type: "POST",
    dataType: "html",
    data: myData,
    success: function (data, textStatus, xhr) {
        //For handling 401 with Authorize attribute on Controller
        if (xhr.getResponseHeader("X-Responded-JSON") != null && JSON.parse(xhr.getResponseHeader("X-Responded-JSON")).status == "401") {
            alert("Unauthorized access returned by Controller");
            //Will redirect to login page
            location.reload(true);
        }
        else {
            alert("Still Authorized");
        }
    },
    error: function (err) {
        alert("There was a technical error");
        console.log(err)
    },
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.