也许我应该在深入探讨标题问题之前备份并扩大范围......
我目前正在用 ASP.NET MVC 1.0 编写一个 Web 应用程序(尽管我的 PC 上确实安装了 MVC 2.0,所以我并不完全限于 1.0)——我已经开始使用标准 MVC 项目,它有你的基本的“欢迎使用 ASP.NET MVC”,并在右上角显示 [Home] 选项卡和 [About] 选项卡。很标准,对吧?
我添加了 4 个新的控制器类,我们称它们为“天文学家”、“生物学家”、“化学家”和“物理学家”。附加到每个新控制器类的是 [Authorize] 属性。
例如,对于 BiologistController.cs
[Authorize(Roles = "Biologist,Admin")]
public class BiologistController : Controller
{
public ActionResult Index() { return View(); }
}
这些 [Authorize] 标签自然会根据角色限制哪些用户可以访问不同的控制器,但我想根据用户所属的角色在我的网站顶部的 Site.Master 页面中动态构建一个菜单。例如,如果“JoeUser”是角色“Astronomer”和“Physicist”的成员,导航菜单会显示:
[首页] [天文学家] [物理学家] [关于]
当然,它不会列出指向“生物学家”或“化学家”控制器索引页面的链接。
或者,如果“JohnAdmin”是角色“Admin”的成员,所有 4 个控制器的链接将显示在导航栏中。
好吧,你明白了……现在是真正的问题……
从这个 StackOverflow 主题关于在 ASP.NET 中构建动态菜单的答案开始,我试图了解如何完全实现这一点。(我是新手,需要更多指导,所以请和我一起裸露。)
答案建议扩展 Controller 类(称为“ExtController”),然后让每个新的 WhatController 从 ExtController 继承。
我的结论是,我需要在这个 ExtController 构造函数中使用反射来确定哪些类和方法具有附加到它们的 [Authorize] 属性来确定角色。然后使用静态字典,将角色和控制器/方法存储在键值对中。
我想象它是这样的:
public class ExtController : Controller
{
protected static Dictionary<Type,List<string>> ControllerRolesDictionary;
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
// build list of menu items based on user's permissions, and add it to ViewData
IEnumerable<MenuItem> menu = BuildMenu();
ViewData["Menu"] = menu;
}
private IEnumerable<MenuItem> BuildMenu()
{
// Code to build a menu
SomeRoleProvider rp = new SomeRoleProvider();
foreach (var role in rp.GetRolesForUser(HttpContext.User.Identity.Name))
{
}
}
public ExtController()
{
// Use this.GetType() to determine if this Controller is already in the Dictionary
if (!ControllerRolesDictionary.ContainsKey(this.GetType()))
{
// If not, use Reflection to add List of Roles to Dictionary
// associating with Controller
}
}
}
这是可行的吗?如果是这样,我如何在 ExtController 构造函数中执行反射以发现 [Authorize] 属性和相关角色(如果有)
还!随意超出此问题的范围,并提出解决此“Dynamic Site.Master Menu based on Roles”问题的替代方法。我是第一个承认这可能不是最好的方法的人。
编辑
经过大量阅读和实验,我想出了自己的解决方案。我的答案见下文。欢迎任何建设性的反馈/批评!