ASP.Net MVC Скрыть / показать пункты меню на основе безопасности

Я работаю над 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> 
   }
}

Я хотел бы переработать это в нечто более читаемое и придумать что-то вроде этого

@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>}

я первоначально добавил следующее К моему базовому конструктору контроллера, думая, что я могу настроить 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;

однако на данный момент в жизненном цикле объект User имеет значение null. Я также попытался создать пользовательский глобальный фильтр, но ViewData тогда недоступен.

каков рекомендуемый способ сделать что-то подобное? Должен ли я просто оставить его, как это было сначала со всем HttpContext-кодом в представлении?

2 ответов


общие советы о ролях

способ, которым я это сделал, - создать пользовательский принципал и сохранить там дополнительную необходимую информацию. В вашем примере это, по крайней мере, будет включать роли для пользователя. таким образом, вы избегаете делать много дополнительных поездок в хранилище пользователей (что, вероятно, база данных 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> }

С кодом 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;
    }
  }
}

Я на самом деле склонен сделать этот шаг дальше и создать ReportsLink в своем ViewModel и установите его, чтобы содержать ссылку, если пользователь авторизован или должен быть пустая строка, если они не являются. Тогда вид просто говорит:

@Model.ReportsLink
@Model.DashboardLink
@Model.AdminLink

в этом случае соответствующая часть ViewModel может быть такой:

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

вот что я закончил делать. Я создал вспомогательный класс MenuSecurity со статическими логическими свойствами для каждого элемента меню, показывающего, какие элементы должны быть видны. Каждое свойство выглядело так

public static bool DashboardVisible
{
   get 
   { 
      return 
         HttpContext.Current.User != null && 
         HttpContext.Current.User.Identity.IsAuthenticated; 
   }
}

затем я убрал мое меню частичный вид, чтобы выглядеть так

@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>}