MvcSiteMapProvider没有为菜单选择角色

时间:2016-03-30 23:19:13

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

我正在使用MVC5,Windows身份验证,结构图DI和自定义角色提供程序。

MVC5的MvcSiteMapProvider没有根据用户角色选择显示菜单的角色。启用安全修整后,它仅显示未定义任何角色属性的菜单项。

我已在控制器上实现并使用ActionFilterAttribute进行授权。控制器根据角色正确地将用户重定向到未经授权的页面,但是菜单没有选择角色属性来隐藏菜单。

自定义RoleProvider具有GetRolesForUser和GetUsersInRole的实现。

任何建议都会有所帮助。

还想知道在SiteMapNodeModel中查找角色属性的位置。我正在考虑自定义在构建菜单时在HtmlHelper中查找权限。

注意:相同的实现在MVC4中正常工作。一旦升级到MVC5并且它不起作用。

由于

1 个答案:

答案 0 :(得分:1)

  

MVC5的MvcSiteMapProvider没有根据用户角色选择显示菜单的角色。启用安全修整后,它仅显示未定义任何角色属性的菜单项。

根据the documentation,roles属性不适用于MVC。它用于与ASP.NET页面互操作。

它仅在安全框架实现IPrincipalIIdentity作为成员身份和身份时才起作用。

  

我已在控制器上实现并使用ActionFilterAttribute进行授权。控制器根据角色正确地将用户重定向到未经授权的页面,但是菜单没有选择角色属性来隐藏菜单。

这很可能是您的问题。安全修整仅查找AuthorizeAttributeAuthorizeAttribute的子类。如果您有子ActionFilterAttribute,则不会将其用于隐藏导航中的链接。

当然,要使标准AuthorizeAttribute起作用,您需要实现IPrincipalIIdentity或使用其中一个预先构建的安全框架。

或者,如果您具有完全自定义的安全性,则可以构建自己的IAclModuleISiteMapNodeVisibilityProvider

  

还想知道在SiteMapNodeModel中查找角色属性的位置。我正在考虑自定义在构建菜单时在HtmlHelper中查找权限。

您无需从SiteMapNodeModel查找角色。相反,您应该从当前上下文中获取角色,并相应地对/Views/Shared/DisplayTemplates/中的菜单模板进行更改。

如果您使用的是支持IPrincipalIIdentity的框架,则可以使用:

@if (User.IsInRole("SomeRole"))
{
    ...
}

另见:

如果要获取为操作方法配置的当前角色,可以构建扩展方法以从当前AuthorizeAttribute读取角色。同样,roles属性仅用于与ASP.NET的互操作性,不应用于纯MVC,因为这意味着您需要在AuthorizeAttribute上复制角色。

public static class ControllerContextExtensions
{
    public static IEnumerable<string> Roles(this ControllerContext controllerContext)
    {
        var controllerType = controllerContext.Controller.GetType();
        var controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
        var actionName = controllerContext.RouteData.Values["action"] as string;
        var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);

        var authorizeAttribute = FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor)
            .Where(f => typeof(AuthorizeAttribute).IsAssignableFrom(f.Instance.GetType()))
            .Select(f => f.Instance as AuthorizeAttribute).FirstOrDefault();

        string[] roles = { };
        if (authorizeAttribute != null && authorizeAttribute.Roles.Length > 0)
        {
            roles = Array.ConvertAll(authorizeAttribute.Roles.Split(','), r => r.Trim());
        }

        return roles;
    }
}

用法

在视图中:

{ var roles = this.ViewContext.Controller.ControllerContext.Roles(); }

在控制器中:

var roles = this.ControllerContext.Roles();

SiteMapNodeModel

获取角色
    var siteMap = MvcSiteMapProvider.SiteMaps.Current;
    var siteMapNode = siteMap.FindSiteMapNodeFromKey(SiteMapNodeModel.Key);
    var roles = siteMapNode.Roles;