Asp.net Mvc custom mechanism to handle unauthorized request
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();
}
Rusi Nova
Updated on June 19, 2022Comments
-
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 401How can i create a filter for this??
-
publicgk over 12 yearsVery elegant solution. A lot better than other solutions on SO. +1
-
Marchy almost 12 yearsDoing 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 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 almost 10 years@Dmitry if you delete filterContext.HttpContext.Response.End(); the status code will be 200
-
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.