Redirecting Unauthorized Controller in ASP.NET MVC

Redirect Unauthorized Page Access in MVC to Custom View

With following change it is working

public class CustomAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//filterContext.Result = new HttpUnauthorizedResult(); // Try this but i'm not sure
filterContext.Result = new RedirectResult("~/Home/Unauthorized");
}

public override void OnAuthorization(AuthorizationContext filterContext)
{
if (this.AuthorizeCore(filterContext.HttpContext))
{
base.OnAuthorization(filterContext);
}
else
{
this.HandleUnauthorizedRequest(filterContext);
}
}

}

And then applying on Controller or Action as below:

[CustomAuthorize(Roles = "Admin")]

With above approach I need to revisit all the controller/actions and change the Authorized attribute! Also some testing will be needed.

I am still not sure why Web.Config route not working as same has been explained in MVC Documentation. May be something has changed in MVC 4!

How to redirect unauthorized users with ASP.NET MVC 6

MVC5 (and older):

You can do this by changing the loginUrl attribute on your web.config. Change it to the desired route:

<authentication mode="Forms">
<forms loginUrl="~/Home/Index" timeout="2880" />
</authentication>

MVC6:

In MVC6 you can try this (inside the Startup.cs):

public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookieAuthenticationOptions>(options =>
{
options.LoginPath = new PathString("/Home/Index");
});
}

Redirecting unauthorized controller in ASP.NET MVC

Create a custom authorization attribute based on AuthorizeAttribute and override OnAuthorization to perform the check how you want it done. Normally, AuthorizeAttribute will set the filter result to HttpUnauthorizedResult if the authorization check fails. You could have it set it to a ViewResult (of your Error view) instead.

EDIT: I have a couple of blog posts that go into more detail:

  • http://farm-fresh-code.blogspot.com/2011/03/revisiting-custom-authorization-in.html
  • http://farm-fresh-code.blogspot.com/2009/11/customizing-authorization-in-aspnet-mvc.html

Example:

    [AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false )]
public class MasterEventAuthorizationAttribute : AuthorizeAttribute
{
/// <summary>
/// The name of the master page or view to use when rendering the view on authorization failure. Default
/// is null, indicating to use the master page of the specified view.
/// </summary>
public virtual string MasterName { get; set; }

/// <summary>
/// The name of the view to render on authorization failure. Default is "Error".
/// </summary>
public virtual string ViewName { get; set; }

public MasterEventAuthorizationAttribute()
: base()
{
this.ViewName = "Error";
}

protected void CacheValidateHandler( HttpContext context, object data, ref HttpValidationStatus validationStatus )
{
validationStatus = OnCacheAuthorization( new HttpContextWrapper( context ) );
}

public override void OnAuthorization( AuthorizationContext filterContext )
{
if (filterContext == null)
{
throw new ArgumentNullException( "filterContext" );
}

if (AuthorizeCore( filterContext.HttpContext ))
{
SetCachePolicy( filterContext );
}
else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
}
else if (filterContext.HttpContext.User.IsInRole( "SuperUser" ))
{
// is authenticated and is in the SuperUser role
SetCachePolicy( filterContext );
}
else
{
ViewDataDictionary viewData = new ViewDataDictionary();
viewData.Add( "Message", "You do not have sufficient privileges for this operation." );
filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
}

}

protected void SetCachePolicy( AuthorizationContext filterContext )
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge( new TimeSpan( 0 ) );
cachePolicy.AddValidationCallback( CacheValidateHandler, null /* data */);
}

}

How can I redirect unauthorized users to a login page based upon the area?

You can create a custom authorize attribute, so inside HandleUnauthorizedRequest you can redirect unauthorized users to specific login page based on area's name:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
else
{
var areaName = filterContext.RouteData.DataTokens["area"];
if (areaName.Equals("Admin"))
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new {controller = "Account", action = "Login", area = "Admin"}));
}
else if(areaName.Equals("Public"))
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Account", action = "Login" }));
}
// other conditions...

}
}
}

As you can see, we used this code to get current area name:

var areaName = filterContext.RouteData.DataTokens["area"];

How to redirect unauthorised users in the controller?

You can use one of the status code page extensions in asp.net core. There are a few to choose from depending on your needs.

You can find more info on them in MS docs.

This article also gives a good description of how to use them (points 3,4,5 in the article).

UseStatusCodePagesWithRedirects might suite your needs and you would use it like this:

In Startup.cs -

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
app.UseStatusCodePagesWithRedirects("/Home/Error/{0}");
//...
}

Then in your HomeController(or wherever you decide) you create an action to handle the status codes -

public IActionResult Error(int statusCode)
{
if (statusCode == 403)
{
return View("YourCustomUnauthorizedView");
}
return View("YourDefaultErrorView");
}

Redirecting an unauthorized user in identity 2.0

For redirecting unauthorized users you don't need to customize AuthorizeAttribute. Simply in Startup.ConfigureAuth(IAppBuilder app) method or your custom OWIN startup method add following line:

public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Error/AccessDenied"),
});
}

But if you want differentiate between unauthenticated users and unauthorized. Write your custom filter like this:

public class MyAuthAttribute: AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if(filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectResult("/Error/AccessDenied");
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}

Then you could add log in url in OWIN startup method:

LoginPath = new PathString("/Account/Login")

ASP.Net MVC 3 Redirect UnAuthorized User not to loginUrl

Just change the page that have to be shown in the web.config (check that the route exists)

<authentication mode="Forms">
<forms loginUrl="~/UnAuthorize" timeout="2880" />
</authentication>

If you, instead, want to redirect to a specific path for every roles you can extend the AuthorizeAttribute with your own. Something like this (not tested, I write this to give you an idea)

public class CheckAuthorize : ActionFilterAttribute
{
public Roles[] Roles { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Your code to get the user
var user = ((ControllerBase)filterContext.Controller).GetUser();

if (user != null)
{
foreach (Role role in Roles)
{
if (role == user.Role)
return;
}
}
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
if user.Role==Role.Administrator
{
redirectTargetDictionary.Add("action", "Unauthorized");
redirectTargetDictionary.Add("controller", "Home");
}
else
{
redirectTargetDictionary.Add("action", "Logon");
redirectTargetDictionary.Add("controller", "Home");
}
filterContext.Result = new RedirectToRouteResult(redirectTargetDictionary);
}
}

ASP.Net Mvc Core Project unauthorized request doesn't redirect to Login page

I updated all nuget packages and it solved all the problems.

asp.net mvc 401 Unauthorized error after redirect

So after a full day of investigation I started to doubt that reason may be in the Authorize Attribute or global filters and began thinking that maybe IIS somehow returns 401 on the redirect requests. But some of other actions with RedirectToAction were found by me and they worked. Besides versions hosted on another IIS had the same problem

Then I started to wonder if there is any Authorization configuration in the MVC project other then default and searched through the project "authorize" which didn't give any unexpected results

But then an idea came up to me to search through all the solution the "redirect" phrase and I finally found the root of the issue...

Sample Image

So on the Application_EndRequest the StatusCode is set to 401 and the error returned for the wrong type of the request

I guess searching for "401" would also help and if the constants were named they would have been found earlier

Redirect to login when unauthorized in ASP.NET Core

You can configure the path using CookieAuthenticationOptions class.

Something like this.

app.UseCookieAuthentication(new CookieAuthenticationOptions {
LoginPath = new PathString("/Login/"),
AuthenticationType = "My-Magical-Authentication",
// etc...
},
});


Related Topics



Leave a reply



Submit