Rusi Nova
Rusi Nova

Reputation: 2655

Asp.net Mvc custom mechanism to handle unauthorized request

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??

Upvotes: 20

Views: 14482

Answers (6)

Omu
Omu

Reputation: 71206

a simple way is to do a check in the SignIn action

public ActionResult SignIn()
{
    if (Request.IsAjaxRequest())
    {
        // you could return a partial view that has this script instead
        return Content("<script>window.location = '" + Url.Action("SignIn", "Account") + "'</script>");
    }
   ...
   return View();

Upvotes: 0

Praveen Prasad
Praveen Prasad

Reputation: 32117

 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*/
});

Upvotes: 29

TWilly
TWilly

Reputation: 4933

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;
}

Upvotes: 4

duyker
duyker

Reputation: 800

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();
}

Upvotes: 1

Tassadaque
Tassadaque

Reputation: 8199

You can use ajaxonly to restrain access to ajax actionresult

Upvotes: 1

Georgi Stoyanov
Georgi Stoyanov

Reputation: 1218

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.

Upvotes: 1

Related Questions