【问题标题】:How do I serve up an Unauthorized page when a user is not in the Authorized Roles?当用户不在授权角色中时,如何提供未经授权的页面?
【发布时间】:2011-01-20 07:27:54
【问题描述】:

我正在像这样使用Authorize 属性:

[Authorize (Roles="Admin, User")]
Public ActionResult Index(int id)
{
    // blah
}

当用户不在指定的角色中时,我得到一个错误页面(找不到资源)。所以我把HandleError属性也放进去。

[Authorize (Roles="Admin, User"), HandleError]
Public ActionResult Index(int id)
{
    // blah
}

如果用户不在指定的角色中,现在它会转到 登录 页面。

当用户不满足所需角色之一时,如何让它转到未经授权的页面而不是登录页面?如果发生不同的错误,我如何区分该错误和未经授权的错误并以不同的方式处理?

【问题讨论】:

标签: c# asp.net-mvc security roles


【解决方案1】:

将这样的内容添加到您的 web.config:

<customErrors mode="On" defaultRedirect="~/Login">
     <error statusCode="401" redirect="~/Unauthorized" />
     <error statusCode="404" redirect="~/PageNotFound" />
</customErrors>

您显然应该创建/PageNotFound/Unauthorized 路由、操作和视图。

编辑:对不起,我显然没有彻底理解这个问题。

问题是当AuthorizeAttribute 过滤器被执行时,它判定用户不符合要求(他/她可能已经登录,但不是正确的角色)。因此它将响应状态代码设置为 401。这被FormsAuthentication 模块拦截,然后执行重定向。

我看到了两种选择:

  1. 禁用默认重定向。

  2. 创建您自己的IAuthorizationFilter。从 AuthorizeAttribute 派生并覆盖 HandleUnauthorizedRequest。在这种方法中,如果用户通过了身份验证,请执行 redirect 到 /Unauthorized

我也不喜欢:defaultRedirect 功能很好,而不是你想自己实现的东西。第二种方法会为用户提供视觉上正确的“您未获得授权”页面,但 HTTP 状态代码将不是所需的 401。

我对 HttpModules 的了解还不够,无法说明这是否可以通过可容忍的 hack 来规避。

编辑 2: 如何通过以下方式实现您自己的 IAuthorizationFilter:从 CodePlex 下载 MVC2 代码并“借用”AuthorizeAttribute 的代码。将 OnAuthorization 方法更改为如下所示

    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (AuthorizeCore(filterContext.HttpContext))
        { 
            HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
        }
        // Is user logged in?
        else if(filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // Redirect to custom Unauthorized page
            filterContext.Result = new RedirectResult(unauthorizedUrl);
        } 
        else {
            // Handle in the usual way
            HandleUnauthorizedRequest(filterContext);
        }
    }

其中unauthorizedUrl 是过滤器上的属性或从 Web.config 中读取。

您也可以从 AuthorizeAttribute 继承并覆盖 OnAuthorization,但您最终会编写几个已经在 AuthorizeAttribute 中的私有方法。

【讨论】:

  • 这不起作用。新的控制器和路由测试正常,但重定向到登录页面显然是在此之前发生的。
  • 嗯,我很确定它过去对我有用。我会在几个小时内检查出来。
  • but the HTTP status codes will not be the desired 401 -- 我可以想出几种方法来解决这个问题。一种方法是在控制器中将Response.StatusCode = 401; 放在return View(“Unauthorized”); 之前。
  • 另一种方法是编写一个自定义的IExceptionAttribute过滤器,将ASP.NET MVC框架中的HandleErrorAttribute替换为更智能的过滤器。见richarddingwall.name/2008/08/17/…
  • 我们真正想要的是覆盖 FormsAuthenticationModule 的行为以仅在用户未通过身份验证时重定向,但这似乎是不可能的。这不好。
【解决方案2】:

您可以通过两种方式做到这一点:

  1. 在 HandleError 属性中指定错误,并给出应该显示的视图:

    [HandleError(ExceptionType = typeof(UnAuthorizedException), View = "UnauthorizedError")]

您可以指定几种不同的异常类型和视图

  1. 创建一个自定义 ActionFilter,在那里检查凭据,如果用户未经授权,则重定向到控制器。:http://web.archive.org/web/20090322055514/http://msdn.microsoft.com/en-us/library/dd381609.aspx

【讨论】:

    【解决方案3】:

    根据您的问题,403 状态代码可能更合适(用户已被识别,但他们的帐户权限不足)。 401适用于您不知道用户拥有什么权限的情况。

    【讨论】:

      【解决方案4】:

      HttpUnauthorizedResult(这是AuthorizeAtrribute 的reuslt)只是将StatusCode 设置为401。所以您可能可以在IIS 中设置401 页面或在web.config 中设置自定义错误页面。当然,您还必须确保访问您的自定义错误页面不需要授权。

      【讨论】:

        【解决方案5】:

        只需重写 AuthorizeAttribute 的 HandleUnauthorizedRequest 方法即可。如果调用此方法,但用户已通过身份验证,则您可以重定向到“未授权”页面。

        public class CustomAuthorizeAttribute : AuthorizeAttribute
        {
            protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
            {
                if (filterContext.HttpContext.User.Identity.IsAuthenticated)
                {
                    filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { Area = "", Controller = "Error", Action = "Unauthorized" }));
                }
                else
                {
                    base.HandleUnauthorizedRequest(filterContext);
                }
            }
        }
        

        【讨论】:

        • 您正在回答一个多年前已经得到充分回答的问题。
        猜你喜欢
        • 1970-01-01
        • 2018-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-15
        • 1970-01-01
        • 1970-01-01
        • 2011-09-29
        相关资源
        最近更新 更多