Asp.net Mvc custom mechanism to handle unauthorized request

13,329

Solution 1

 public class MyCustomAuthorize : AuthorizeAttribute
{
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            //if ajax request set status code and end Response
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.HttpContext.Response.StatusCode = 401;
                filterContext.HttpContext.Response.End();
            }

            base.HandleUnauthorizedRequest(filterContext);
        }
}

Create a filter like above, it will return status code 401 for unauthorized request if request is made thru ajax.

If you are using jQuery you can do as below

jQuery.ajax({
statusCode: {
    401: function() {
      alert('unauthrized');
    },

  /*other options*/
});

Solution 2

In addition to the accepted answer, I needed to put this line of code in to prevent FormsAuthentication from redirecting to the login page..

filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

I then removed filterContext.HttpContext.Response.End();

var unauthorizedResult = new JsonResult
{
    Data = new ErrorResult() {Success = 0, Error = "Forbidden"},
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
    };
    // status code
    filterContext.HttpContext.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
    // return data
    filterContext.Result = unauthorizedResult;
    filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
}

Solution 3

Your problem is not with AJAX request, your problem is returning HTTP 401 Unauthorized response, because you use forms authentication. This response code tells the framework that it should redirect the user-agent to your login page with a HTTP 302 response instead. That's why it was easy to setup the "normal" request redirect - it's done automatically.
To answer your question, I had similar problem and the solution I ended up with was not using forms authentication. I implemented a custom authorization attribute that handles both cases manually instead. I'm not sure if this is the best approach, but it does work. I'm interested in what others think of this solution or what other solutions there are.
Fortunately, you can still use the FormsAuthentication class to handle cookies for you, but you have to delete the forms authentication configuration from your Web.config file. When the user logs in you use FormsAuthentication.SetAuthCookie to, well, set a cookie (you are probably doing this already). Second, in your authorization attribute, you get the cookie from the request and use FormsAuthentication.Decrypt to decrypt it. If it exists and is valid, you set the user in the HttpContext based on this cookie, because forms authentication won't do it for you anymore. If it doesn't you either redirect to the login page or return 401, depending on whether it's an AJAX call or not.

Solution 4

You can use ajaxonly to restrain access to ajax actionresult

Solution 5

You can just return a HttpUnauthorizedResult.

Note: This could cause the MVC framework to return you to the login page.

public ActionResult FailResult()
{
        return new HttpUnauthorizedResult();
}
Share:
13,329
Rusi Nova
Author by

Rusi Nova

Updated on June 19, 2022

Comments

  • Rusi Nova
    Rusi Nova almost 2 years

    For my website i want following behaviors for secured controller(or action)

    if a user makes a normal request redirect to login page (which i have easily able to do)

    if request is Ajax type Request.IsAjaxRequest()==true, return status code 401

    How can i create a filter for this??

  • publicgk
    publicgk over 12 years
    Very elegant solution. A lot better than other solutions on SO. +1
  • Marchy
    Marchy almost 12 years
    Doing this throws an HTTPException: "Server cannot set status after HTTP headers have been sent." Is there some order that this attribute needs to run in relation to other action filters?
  • Dmitry Efimenko
    Dmitry Efimenko almost 11 years
    @Marchy if you delete line filterContext.HttpContext.Response.End(); the exception will be gone. Though I'm not sure what else would be affected and would like to know the purpose of this line there.
  • Antipod
    Antipod almost 10 years
    @Dmitry if you delete filterContext.HttpContext.Response.End(); the status code will be 200
  • Amir Chatrbahr
    Amir Chatrbahr over 9 years
    @Marchy Have you forgotten last line? base.HandleUnauthorizedRequest(filterContext); I had same issue simply because of not executing this line.