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

Guy*_*Guy 73 c# asp.net-mvc redirect authorization

我在ASP.NET MVC中有一个控制器,我已将其限制为admin角色:

[Authorize(Roles = "Admin")]
public class TestController : Controller
{
   ...
Run Code Online (Sandbox Code Playgroud)

如果不在Admin角色中的用户导航到此控制器,则会显示空白屏幕.

我想要做的是将它们重定向到View,其中显示"您需要处于Admin角色才能访问此资源".

我想到的一种方法是在IsUserInRole()上检查每个操作方法,如果不在角色中,则返回此信息视图.但是,我必须在每个打破DRY主体的Action中加入它,显然很难维护.

tva*_*son 69

基于AuthorizeAttribute创建自定义授权属性并覆盖OnAuthorization以执行检查完成的方式.通常,如果授权检查失败,AuthorizeAttribute会将过滤结果设置为HttpUnauthorizedResult.您可以将其设置为ViewResult(Error视图).

编辑:我有一些博客文章更详细:

例:

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


    }
Run Code Online (Sandbox Code Playgroud)


Len*_*rri 26

您可以HandleUnauthorizedRequest在自定义内部使用可覆盖的内容AuthorizeAttribute

像这样:

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" }
    });
}
Run Code Online (Sandbox Code Playgroud)

你也可以这样做:

private class RedirectController : Controller
{
    public ActionResult RedirectToSomewhere()
    {
        return RedirectToAction("Action", "Controller");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过HandleUnauthorizedRequest以下方式在方法中使用它:

filterContext.Result = (new RedirectController()).RedirectToSomewhere();
Run Code Online (Sandbox Code Playgroud)


小智 10

"tvanfosson"的代码给了我"执行子请求时出错"..我已经改变了OnAuthorization,如下所示:

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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

这很好用,我在错误页面上显示TempData.感谢代码片段的"tvanfosson".我正在使用Windows身份验证,_isAuthorized只是HttpContext.User.Identity.IsAuthenticated ...


Mic*_*lGG 5

我遇到过同样的问题.我没有找出MVC代码,而是选择了一个看似有效的廉价黑客.在我的Global.asax类中:

member x.Application_EndRequest() =
  if x.Response.StatusCode = 401 then 
      let redir = "?redirectUrl=" + Uri.EscapeDataString x.Request.Url.PathAndQuery
      if x.Request.Url.LocalPath.ToLowerInvariant().Contains("admin") then
          x.Response.Redirect("/Login/Admin/" + redir)
      else
          x.Response.Redirect("/Login/Login/" + redir)
Run Code Online (Sandbox Code Playgroud)