MVC5 的 MvcSiteMapProvider 没有根据用户角色选择角色来显示菜单。启用安全修剪后,它仅显示未定义任何角色属性的菜单项。
根据the documentation,角色属性不适用于 MVC。它用于与 ASP.NET 页面的互操作。
它仅在安全框架像 Membership 和 Identity 一样实现 IPrincipal 和 IIdentity 时起作用。
我在控制器上实现了 ActionFilterAttribute 并用于授权。控制器根据角色正确地将用户重定向到未经授权的页面,但菜单没有选择角色属性来隐藏菜单。
这很可能是您的问题。安全修整只查找AuthorizeAttribute 和AuthorizeAttribute 的子类。如果您有子类ActionFilterAttribute,它将不会用于隐藏导航中的链接。
当然,要使标准 AuthorizeAttribute 工作,您需要实现 IPrincipal 和 IIdentity 或使用具有相同功能的预构建安全框架之一。
或者,如果您有完全自定义的安全性,您可以构建自己的 IAclModule 或 ISiteMapNodeVisibilityProvider。
还想知道在 SiteMapNodeModel 中何处查找角色属性。我正在考虑在构建菜单时自定义以在 HtmlHelper 中查找权限。
您无需从SiteMapNodeModel 中查找角色。相反,您应该从当前上下文中获取角色,并相应地更改 /Views/Shared/DisplayTemplates/ 中的菜单模板。
如果您使用的框架支持IPrincipal 和IIdentity,则可以使用:
@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;