Redirecting unauthorized controller in ASP.NET MVC

I have a controller in ASP.NET MVC that I've restricted to the admin role:

[Authorize(Roles = "Admin")]
public class TestController : Controller
{
   ...

If a user who is not in the Admin role navigates to this controller they are greeted with a blank screen.

What I would like to do is redirect them to View that says "you need to be in the Admin role to be able to access this resource."

One way of doing this that I've thought of is to have a check in each action method on IsUserInRole() and if not in role then return this informational view. However, I'd have to put that in each Action which breaks the DRY principal and is obviously cumbersome to maintain.


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 */);
            }
    
    
        }
    

    You can work with the overridable HandleUnauthorizedRequest inside your custom AuthorizeAttribute

    Like this:

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // Returns HTTP 401 by default - see HttpUnauthorizedResult.cs.
        filterContext.Result = new RedirectToRouteResult(
        new RouteValueDictionary 
        {
            { "action", "YourActionName" },
            { "controller", "YourControllerName" },
            { "parameterName", "YourParameterValue" }
        });
    }
    

    You can also do something like this:

    private class RedirectController : Controller
    {
        public ActionResult RedirectToSomewhere()
        {
            return RedirectToAction("Action", "Controller");
        }
    }
    

    Now you can use it in your HandleUnauthorizedRequest method this way:

    filterContext.Result = (new RedirectController()).RedirectToSomewhere();
    

    The code by "tvanfosson" was giving me "Error executing Child Request".. I have changed the OnAuthorization like this:

    public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
    
            if (!_isAuthorized)
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
            else if (filterContext.HttpContext.User.IsInRole("Administrator") || filterContext.HttpContext.User.IsInRole("User") ||  filterContext.HttpContext.User.IsInRole("Manager"))
            {
                // is authenticated and is in one of the roles 
                SetCachePolicy(filterContext);
            }
            else
            {
                filterContext.Controller.TempData.Add("RedirectReason", "You are not authorized to access this page.");
                filterContext.Result = new RedirectResult("~/Error");
            }
        }
    

    This works well and I show the TempData on error page. Thanks to "tvanfosson" for the code snippet. I am using windows authentication and _isAuthorized is nothing but HttpContext.User.Identity.IsAuthenticated...

    链接地址: http://www.djcxy.com/p/30176.html

    上一篇: 在MVC中最好拥有巨大的控制器或许多控制器?

    下一篇: 在ASP.NET MVC中重定向未授权的控制器