ASP.Net MVC Скрыть / Показать пункты меню на основе безопасности - PullRequest
15 голосов
/ 07 декабря 2011

Я работаю на сайте 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 является нулевым. Я также пытался создать собственный глобальный фильтр, но ViewData недоступен.

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

Ответы [ 2 ]

10 голосов
/ 08 декабря 2011

Общие советы по ролям

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

Вот что я в итоге сделал. Я создал вспомогательный класс 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>}
...