ASP.NET MVC - How to show an unauthorized error on the login page?

In my ASP.NET MVC application, I have most of the controllers decorated with

[Authorize(Roles="SomeGroup")] 

When a user does not have permission to access something, they are sent to "~ / Login", which is the "Login" action on my account controller.

How can I determine that the user has reached the login page due to non-authorization so that I can show the corresponding error?

+45
c # authorization asp.net-mvc
Sep 30 '09 at 15:07
source share
7 answers

You can find the value ?ReturnUrl= querystring or create your own authorization filter and set a field in TempData indicating the reason.

Here is a simple custom filter that will do the trick:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class CustomAuthorizeAttribute : AuthorizeAttribute { // NOTE: This is not thread safe, it is much better to store this // value in HttpContext.Items. See Ben Cull answer below for an example. private bool _isAuthorized; protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) { _isAuthorized = base.AuthorizeCore(httpContext); return _isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); if(!_isAuthorized) { filterContext.Controller.TempData.Add("RedirectReason", "Unauthorized"); } } } 

Then, in your opinion, you can do something like this:

 @if(TempData["RedirectReason"] == "Unauthorized") { <b>You don't have permission to access that area</b> } 

(Although I would recommend a better approach than these magic lines, but you get the point)

+28
Sep 30 '09 at 15:21
source share

UPDATE (Jun 2015): @ daniel-lidström correctly pointed out that you should not use Response.Redirect in an ASP.NET MVC application. For more information on why, please see this link: Response.Redirect and ASP.NET MVC - do not mix .

UPDATE (September 2014): I am not sure when HandleUnauthorizedRequest was added to AuthorizeAttribute, but in any case I managed to refine the AuthorizeRedirect code into something smaller and simpler.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthorizeRedirect : AuthorizeAttribute { public string RedirectUrl = "~/Error/Unauthorized"; protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.Result = new RedirectResult(RedirectUrl); } } } 



Original answer Below (still fully functional)

I left this answer here, because it still gives you an idea of ​​how the authorization pipeline works.

For those who are still landing here, I edited Ben Sheyrman's answer to automatically redirect to an unauthorized page when the user logged in, but did not log in. You can change the redirect path using the name parameter RedirectUrl.

EDIT: I made the solution thread safe thanks to the advice of Tarynn and MSDN

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthorizeRedirect : AuthorizeAttribute { private const string IS_AUTHORIZED = "isAuthorized"; public string RedirectUrl = "~/error/unauthorized"; protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) { bool isAuthorized = base.AuthorizeCore(httpContext); httpContext.Items.Add(IS_AUTHORIZED, isAuthorized); return isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); var isAuthorized = filterContext.HttpContext.Items[IS_AUTHORIZED] != null ? Convert.ToBoolean(filterContext.HttpContext.Items[IS_AUTHORIZED]) : false; if (!isAuthorized && filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl); } } } 
+76
Mar 08 '11 at 23:15
source share

The Ben Kull method works well, but remember that there are two AuthorizeAttribute classes - one in System.Web.HTTP (using the Web API) and the other in System.Web.Mvc. The Ben method uses the System.Web.Mvc class. For clarity, I suggest using the full path.

If you use the Web API with MVC, you will need to implement two filters:

 public class AuthorizeRedirectMVCAttribute : System.Web.Mvc.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.Result = new RedirectResult("~/Account/AccessDenied"); } } } public class AuthorizeRedirectAPIAttribute : System.Web.Http.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { base.HandleUnauthorizedRequest(actionContext); if (actionContext.RequestContext.Principal.Identity.IsAuthenticated) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden); } } } 

Please note that asp.net will allow you to decorate your MVC controller with an API filter - it just won’t work as you expect, so save your attribute names explicitly.

+5
Feb 05 '16 at 15:59
source share

If you have a controller and you do not want to have a URL in the code, you can also redirect this path. It will not change the URL in the address bar of the browser, so the user will never see the URL for the unauthorized page. This was written in MVC 3. This method will also work if you want to redirect them to the login page or if you want to redirect them to the page just to tell them that they are not authorized. I had a section in the program that some user did not have rights, but they logged in, so this is what I used.

 public class AuthorizedRedirect : AuthorizeAttribute { protected override bool AuthorizeCore(HttpContextBase httpContext) { bool isAuthorized = base.AuthorizeCore(httpContext); return isAuthorized; } protect override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.RequestContext.RouteData.Values["controller"] = "error"; filterContext.Result = new ViewResult { ViewName = "unauthorized" }; } 
+4
Sep 26 '11 at 18:58
source share

And an even simpler version using FormsAuthentication settings. For those who are not familiar with the contract, Contract.Requires is a .NET 4 add-on. Pros and Cons of Using Code Contracts .

 public class RequiresAttribute : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { Contract.Requires(filterContext != null); HttpContextBase context = filterContext.RequestContext.HttpContext; if (context.User.Identity.IsAuthenticated) { // user does not possess the required role permission string url = context.GetCustomErrorUrl(401); context.Response.Redirect(url); } else { // redirect the user to the login page string extraQueryString = context.Request.RawUrl; FormsAuthentication.RedirectToLoginPage(extraQueryString); } } } 
+2
Sep 27 2018-11-11T00:
source share

Switching from a divide_byzero answer, even if you don't have a controller, you can still use HandleUnauthorizedRequest to change the redirect.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthoriseRedirect : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.RequestContext.HttpContext.Response.Redirect("UrlToRedirectTo"); } } 

It is useful if you have an outdated web form site that you will convert to MVC for a longer period of time .....!

+1
Nov 18 '13 at 6:35
source share

I like what is published by Brian Vander Plaats, several enhancements added:

 /// <summary> /// Authorize or redirect to an unauthorized MVC action if the user does not have the required roles /// (an unauthenticated user will be redirected to the defualt sign in action) /// <para>Decorate an action or a controller like this [AuthorizeAndRedirect(Roles = "RoleName")]</para> /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class AuthorizeOrRedirectAttribute : System.Web.Mvc.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { var routeData = new RouteData(); routeData.Values.Add("controller", "Error"); routeData.Values.Add("action", "Unauthorized"); filterContext.Result = new RedirectToRouteResult(routeData.Values); } } } /// <summary> /// Authorize or redirect to an unauthorized API action if the user does not have the required roles /// (an unauthenticated user will be redirected to the defualt sign in action) /// <para>Decorate an action or a controller like this [AuthorizeAndRedirect(Roles = "RoleName")]</para> /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class AuthorizeOrRedirectApiFilterAttribute : System.Web.Http.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { base.HandleUnauthorizedRequest(actionContext); if (actionContext.RequestContext.Principal.Identity.IsAuthenticated) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); } } } 
0
Apr 7 '16 at 20:07 on
source share



All Articles