how can mvc return Unauthorized code without redirecting to LogIn view
Solution 1
To prevent login page redirection you must set SuppressFormsAuthenticationRedirect
property of HttpContext.Response
to true;
HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
Solution 2
What you are experiencing is a hole in ASP.NET MVC (I hope they fix one day).
The standard operating model for ASP.NET is that if a 401 Http Status code is detected, then as you are experiencing, it automatically redirects to the login page, and this happens even if you have come in via an Ajax call. Unfortunately I have also not found any way to change this behaviour.
What I do instead is return an alternative, otherwise unused Http Status Code that I can detect in the client and handle in the appropriate manner.
Therefore within my Authentication Filter, if its an Ajax request I return 449 otherwise the standard 401. Then on the client I can examine the XMLHttpRequest.status and take appropriate action if 449 is detected.
Solution 3
You can create a simple authorization attribute filter (extend the AuthorizeAttribute class) and use it for your access control. Then try something like this:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() || string.Compare("GET", filterContext.HttpContext.Request.HttpMethod, true) != 0)
{
// Returns 403.
filterContext.Result = new HttpStatusCodeResult((int)HttpStatusCode.Forbidden);
}
else
{
// Returns 401.
filterContext.Result = new HttpUnauthorizedResult();
}
}
The effect is that, POST and AJAX requests will always receive a 403 response which makes it easier for you to handle your ajax submits in javascript. As for the non-ajax posts, it doesn't really matter what the response is because your user shouldn't have got his hands on the submit form in the first place :)
As for the other requests, the method returns 401 that the formsAuthentiction module will pick up and then redirect your response to the login page.
Solution 4
This is the way I managed to prevent redirection to the login page.
In my case when I wanted to receive the status code in order to handle it in javascript :
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
Context.Response.Clear();
Context.Response.StatusCode = 401;
}
}
Related videos on Youtube
mateo
Updated on May 03, 2022Comments
-
mateo almost 2 years
My MVC web application serves two types of users.
- First one over standard web browser;
- Second one over REST returning only JSON data.
Additionally,
- Both require Authentication and authorization;
- Both scenarios are differentiated based on the route so that I know what content to serve.
When users access the application, if they are not logged in, the application should react differently.
- In the first case it should return the default LogIn page (this is fine).
- In the second case it should return a 401 Unauthorized code only.
I'm used to working with WCF REST service where I could raise an exception like this:
throw new WebProtocolException(System.Net.HttpStatusCode.Unauthorized, exc.Message, exc);
and receive a 401 message. The problem with the same approach within MVC when I put the
statusCode
like this:HttpContext.Response.StatusCode = (Int32)HttpStatusCode.Unauthorized
it always redirects to the LogIn page.
How can I do this?
I've tried overriding the
AuthorizeAttribute
and handling theOnAuthorization
function, but still as soon as I set thestatusCode
to 401 it gets redirected to the LogIn page.-
Raciel R. about 11 years@JP This is weird, I have my webapi exposed in my MVC4 application and I don't see this behavior. The System.Web.Http.Authorize attribute used in the ApiControllers uses the Thread.CurrentPrincipal.Identity.IsAuthenticated method while the System.Web.Mvc.Authorize attribute used in the MvcControllers uses the HttpContext.User.Identity.IsAuthenticated. Are you populating the Principal when you login through your login webapi endpoint? How are you identifying subsequent request from the authenticated user? Are you using any token?
-
jamiebarrow over 11 yearsYou may find this kind of approach is not applicable if you aren't using Integrated mode for the app pool.
-
Ferran Salguero over 10 yearsThis property is only available in .NET 4.5 (msdn)
-
Ferran Salguero over 10 yearsCombining it with .ajaxError() you can check the status code to redirect or reload the full page
-
Kambiz Shahim over 10 years@hellyeah for the previous versions you can see here
-
Jeff over 10 yearsWhere do i put this line of code? Do I have to make a custom filter? Or an HTTP Module?
-
Kambiz Shahim over 10 years@Jeff You can use it in a action method of the controller and in a custom action filter as well.
-
Artyom almost 8 yearsOn how to use this here is an interesting article at codeproject.com/Articles/655086/…
-
Zapnologica over 5 yearsIs this per request? So I just put this in the action method where I donot want it to return. Ie and ajax data post?
-
Kambiz Shahim over 5 years@Zapnologica Yes it is
-
Zapnologica about 5 yearsWeird, it didnt work for me. I return a new Unatuthorized and it returns a 200 with login screen.