MVCSiteMapNode需要多个角色

时间:2014-07-22 14:53:20

标签: asp.net-mvc asp.net-mvc-4 roles mvcsitemapprovider

我使用MVCSiteMap设置了菜单,我有这个节点:

<mvcSiteMapNode title="Courses Form" controller="Booking" action="Course" roles="CORLIC, VIEWCOBO"/>

我正在尝试强制执行此节点必须具有“CORLIC”和“VIEWCOBO”角色才能看到它,但这当然意味着如果用户具有上述任一项,它将会显示。

这可能吗?

感谢。

1 个答案:

答案 0 :(得分:1)

roles属性用于与ASP.NET的互操作性,不应在仅MVC应用程序中使用。

对于MVC,如果您已经在控制器操作上定义了AuthorizeAttribute,则MvcSiteMapProvider会自动选择它们并在启用security trimming时相应地隐藏匹配的节点。

[Authorize]
public ActionResult Course()
{
    return View();
}

[Authorize]
[HttpPost]
public ActionResult Course(CourseModel model)
{
    if (ModelState.IsValid)
    {
        // Implementation omitted
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

默认AuthorizeAttribute接受角色,但它的工作方式与roles属性相同 - 也就是说,用户所在的任何角色都会使其成功。

但是,您可以自己继承AuthorizeAttribute并覆盖IsAuthorized method以根据需要更改逻辑。

public class SpecialAuthorizeAttribute : AuthorizeAttribute
{
    private string _requiredRoles;
    private string[] _requiredRolesSplit = new string[0];

    /// <summary>
    /// Gets or sets the required roles. The user must be a member of all roles for it to succeed.
    /// </summary>
    /// <value>
    /// The roles string.
    /// </value>
    /// <remarks>Multiple role names can be specified using the comma character as a separator.</remarks>
    public string RequiredRoles
    {
        get { return _requiredRoles ?? String.Empty; }
        set
        {
            _requiredRoles = value;
            _requiredRolesSplit = SplitString(value);
        }
    }

    /// <summary>
    /// Determines whether access for this particular request is authorized. This method uses the user <see cref="IPrincipal"/>
    /// returned via <see cref="HttpRequestContext.Principal"/>. Authorization is denied if the user is not authenticated,
    /// the user is not in the authorized group of <see cref="Users"/> (if defined), or if the user is not in any of the authorized 
    /// <see cref="Roles"/> (if defined).
    /// </summary>
    /// <param name="actionContext">The context.</param>
    /// <returns><c>true</c> if access is authorized; otherwise <c>false</c>.</returns>
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        if (actionContext == null)
        {
            throw new ArgumentNullException("actionContext");
        }

        IPrincipal user = actionContext.ControllerContext.RequestContext.Principal;
        if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
        {
            return false;
        }

        // Ensure all of the roles in RequiredRoles are present.
        if (_requiredRolesSplit.Length > 0 && !_requiredRolesSplit.All(user.IsInRole))
        {
            return false;
        }

        // Call the base class to check the users and roles there.
        return base.IsAuthorized(actionContext);
    }

    /// <summary>
    /// Splits the string on commas and removes any leading/trailing whitespace from each result item.
    /// </summary>
    /// <param name="original">The input string.</param>
    /// <returns>An array of strings parsed from the input <paramref name="original"/> string.</returns>
    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();
    }
}

然后,您可以使用新属性指定所需的角色。

[SpecialAuthorize(RequiredRoles = "CORLIC, VIEWCOBO")]
public ActionResult Course()
{
    return View();
}

[SpecialAuthorize(RequiredRoles = "CORLIC, VIEWCOBO")]
[HttpPost]
public ActionResult Course(CourseModel model)
{
    if (ModelState.IsValid)
    {
        // Implementation omitted
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

另一种可能的选择是将FluentSecurity用作shown here。要使FluentSecurity v2.0与MvcSiteMapProvider一起使用,您需要将HandleSecurityAttribute code复制到项目中并将其更改为从AuthorizeAttribute而不是Attribute继承,然后按照FluentSecurity文档中的指定使用它。