Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

In my ASP.NET MVC app, I have most controllers decorated with

[Authorize(Roles="SomeGroup")] 

When a user is not authorized to access something, they are sent to "~/Login" which is the Login action on my Account controller.

How can I determine that a user has reached the login page because of not being authorized so that I can show an appropriate error?

like image 213
Ronnie Overby Avatar asked Sep 30 '09 15:09

Ronnie Overby


2 Answers

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

UPDATE (Sep 2014): I'm not sure when HandleUnauthorizedRequest was added to the AuthorizeAttribute, but either way I've been able 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've left this answer here as it still gives you an insight as to how the Authorization pipeline works.

For anyone still landing here, I've edited Ben Scheirman's answer to automatically redirect to an unauthorized page when the user is logged in but not authorized. You can change the redirect path using the name parameter RedirectUrl.

EDIT: I've 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);         }     } } 
like image 64
Ben Cull Avatar answered Sep 23 '22 13:09

Ben Cull


You can look for the ?ReturnUrl= querystring value, or you can create your own authorization filter & 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's 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 view, you can do something like this:

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

(Though I'd recommend a better approach than these magic strings, but you get the point)

like image 21
Ben Scheirman Avatar answered Sep 24 '22 13:09

Ben Scheirman