MVC限制/重定向到区域的角色

时间:2014-06-12 20:17:42

标签: asp.net-mvc asp.net-mvc-4 redirect forms-authentication

我正试图弄清楚如何做到这一点,我似乎无法想出尝试。

我已经创建了一个过滤器来重定向经过身份验证的请求,因此经过身份验证的用户无法重新访问登录页面。这一切都很好,花花公子。

但是,系统中只有一个角色只能访问应用程序中的单个区域,对主区域或其他区域中其他控制器的任何请求都应将用户重定向到此区域。

我不只是想向这些用户展示未经授权的消息,如果他们试图查看他们所在区域以外的任何内容,我宁愿将其重定向回他们的区域。

实现这一目标的不同方法有哪些(请包含优缺点)?

修改

为了清楚这一点,我希望这样做的原因是消除潜在的边缘情况,其中特定角色的用户从浏览器历史记录中输入URL或手动将其带到应用程序的另一个区域不应该访问。

对于基本角色为User的应用程序的默认区域,只需使用基本AuthorizeAttribute即可确保请求获得授权(就像大多数用户一样)将在注册时被授予用户角色。

对于其他区域,有特定的角色可以正确地向没有给定角色的用户显示401未经授权的页面。

在这种特殊情况下,某个类型的用户是使用特定角色创建的, NOT 是基本User角色,但同时他们的请求将被视为{ {1}}。

3 个答案:

答案 0 :(得分:2)

最简单,最有效的方法可能是创建一个特定于您需求的自定义AuthorizationAttribute:

public class ThatSpecificRoleAttribute : AuthorizeAttribute
{
  protected override bool AuthorizeCore(HttpContextBase httpContext)
  {
    // not sure what is EXACTLY needed so here is all the stuff I
    // think someone might need
    var rd = httpContext.Request.RequestContext.RouteData;
    string currentAction = rd.GetRequiredString("action");
    string currentController = rd.GetRequiredString("controller");
    string currentArea = rd.Values["area"] as string;

    if (httpContext.User != null
        && httpContext.User.Identity != null
        && httpContext.User.Identity.IsAuthenticated 
        && httpContext.User.IsInRole("ThatSpecificRole")
        && currentController != "Home")
    {
      // alternatively you could also...
      // httpContext.Controller.TempData["ThatSpecificRoleError401"] = true;

      return false;
    }
    return true
  }

  protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
  {
    filterContext.Result = new RedirectToAction("Index", Home);
  }
}

然后全局注册(确保它是第一个添加的auth属性):

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ThatSpecificRoleAttribute());
    }
}

我知道其他人已经提到了类似的东西,但这是非常具体的(MVC支持多个授权属性,fyi)。

优点:

  • 如果有人将此添加到控制器或方法中,您不必担心,它是全局的
  • 只做你需要的,其他人(匿名和没有角色的人)正常使用系统。
  • 这将重定向它们,你可以看到TempData是否存在并给他们一个很好的消息,让他们知道他们被重定向(选项)。

缺点:

  • 每个请求都会检查此授权。它应该被缓存,因此性能损失非常小但仍然存在。

答案 1 :(得分:0)

我遇到了类似的问题,最后我使用了一个小黑客。

当您返回HttpUnauthorized结果时,用户将自动重定向到Web.config中定义的Login页面(在该部分中)

但是,我没有重定向到登录页面,而是重定向到另一个操作。在此操作中,我检查用户是否确实已登录。如果是,我检查他可以查看的区域,并将用户重定向到该区域。如果没有找到区域,或者用户根本没有登录,我手动重定向到登录页面。

希望这有帮助!

答案 2 :(得分:0)

创建接受被拒绝角色的自定义授权属性

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    private string _rejectedRoles;
    private string[] _rejectedRoleSplit = new string[0];

    public string RejectedRoles
    {
        get { return _rejectedRoles ?? String.Empty; }
        set
        {
            _rejectedRoles = value;
            _rejectedRoleSplit = SplitString(value);
        }
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
        {
            throw new ArgumentNullException("httpContext");
        }

        var user = httpContext.User;
        if (!user.Identity.IsAuthenticated)
            return false;

        if (_rejectedRoleSplit.Length > 0 && _rejectedRoleSplit.Any(user.IsInRole))
            return false;

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.Result = new RedirectToRouteResult("default area route");
    }

    internal static string[] SplitString(string original)
    {
        if (String.IsNullOrEmpty(original))
        {
            return new string[0];
        }

        var split = from piece in original.Split(',')
                    let trimmed = piece.Trim()
                    where !String.IsNullOrEmpty(trimmed)
                    select trimmed;
        return split.ToArray();
    }
}

并通过以下方式装饰控制器:

[CustomAuthorize(RejectedRoles = "SomeRole")]