ASP.Net MVC隐藏/显示基于安全性的菜单项

Gav*_*vin 15 asp.net-membership asp.net-mvc-3

我正在开发一个ASP.Net MVC 3站点._Layout主视图包含一个菜单,我想隐藏菜单中的一些项目,具体取决于您是否已登录以及您所处的角色.

目前使用这样的代码

@if (HttpContext.Current.User.Identity.IsAuthenticated)
{
   <li id="MyLearningTab">@Html.ActionLink("My Learning", "MyLearning", "Learning")</li> 
   if (HttpContext.Current.User.IsInRole("Reporters"))
   {
      <li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li>
   }
   if (HttpContext.Current.User.IsInRole("Administrators"))
   {
      <li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li>
      <li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li> 
   }
}
Run Code Online (Sandbox Code Playgroud)

我想把它重构为更具可读性的东西,并想出类似的东西

@if ((bool)ViewData["MenuMyLearning"]){<li id="MyLearningTab">@Html.ActionLink("My Learning", "MyLearning", "Learning")</li> }    
@if((bool)ViewData["MenuReports"]){<li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li>}
@if ((bool)ViewData["MenuDashboard"]){<li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li>}
@if ((bool)ViewData["MenuAdmin"]){<li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li>}
Run Code Online (Sandbox Code Playgroud)

我最初将以下内容添加到我的基本控制器构造函数中,以为我可以在那里为这些属性设置ViewData

ViewData["MenuDashboard"] = User != null && User.Identity.IsAuthenticated && User.IsInRole("Administrators");
ViewData["MenuAdmin"] = User != null && User.Identity.IsAuthenticated && User.IsInRole("Administrators");
ViewData["MenuReports"] = User != null && User.Identity.IsAuthenticated && User.IsInRole("Reportors");
ViewData["MenuMyLearning"] = User != null && User.Identity.IsAuthenticated;
Run Code Online (Sandbox Code Playgroud)

但事实证明,生命周期中此时User对象为null.我也尝试过创建自定义全局过滤器,但ViewData不可访问.

做这样的事情的推荐方法是什么?我是否应该首先使用视图中的所有HttpContext代码?

Tom*_*ler 10

关于角色的一般建议

我这样做的方法是创建一个自定义主体并在那里存储额外的所需信息.在您的示例中,这至少包括用户的角色.这样你就可以避免多次访问用户存储(可能是SQL数据库).

看看我的这个问题,我给出了我成功使用的代码:基本控制器ASP.NET MVC 3中的自定义主体是非常低效的吗?

请注意,我将自定义主体存储在缓存中而不是存储在会话中(仅仅是关于会话劫持的偏执).

我喜欢这种方法,因为它非常易于扩展.例如,我已经扩展了这一点,以便在用户通过Facebook登录时公开Facebook凭据.

请记住,如果您正在缓存数据,则需要记住在更改时更新它!

回答你的问题

只是要添加,在您的具体情况下,您应该将这些额外信息存储在一个ViewModel,然后您的视图会说:

@if(ShowReports) { <li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li> }
@if(ShowDashboard) { <li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li> }
@if(ShowAdmin { <li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li> }
Run Code Online (Sandbox Code Playgroud)

使用ViewModel代码说:

public bool ShowReports {get;set;}
public bool ShowDashboard {get;set;}
public bool ShowAdmin {get;set;}

public void SetViewModel()
{
  if (User.Identity.IsAuthenticated)
  {
    if (HttpContext.Current.User.IsInRole("Reporters"))
    {
       ShowReports = true;
    }
    if (HttpContext.Current.User.IsInRole("Administrators"))
    {
       ShowDashboard = true;
       ShowAdmin = true;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我实际上倾向于更进一步,ReportsLink在我的内容中创建一个ViewModel并设置它以包含用户被授权的链接,如果不是,则将其设置为空字符串.然后视图说:

@Model.ReportsLink
@Model.DashboardLink
@Model.AdminLink
Run Code Online (Sandbox Code Playgroud)

在这种情况下,ViewModel的相关部分可能是这样的:

ReportLink = new MvcHtmlString(HtmlHelper.GenerateLink(HttpContext.Current.Request.RequestContext, System.Web.Routing.RouteTable.Routes, "linktext", "routename", "actionname", "controllername", null, null));
Run Code Online (Sandbox Code Playgroud)


Gav*_*vin 8

这就是我最终做的事情.我为每个菜单项创建了一个名为MenuSecurity的辅助类,其中包含静态布尔属性,显示哪些项应该可见.每个属性都是这样的

public static bool DashboardVisible
{
   get 
   { 
      return 
         HttpContext.Current.User != null && 
         HttpContext.Current.User.Identity.IsAuthenticated; 
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我整理了我的菜单局部视图,看起来像这样

@if (MenuSecurity.ReportsVisible){<li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li>}
@if (MenuSecurity.DashboardVisible){<li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li>}
@if (MenuSecurity.AdminVisible){<li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li>}
Run Code Online (Sandbox Code Playgroud)