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 в данный момент жизненного цикла является нулевым. Я также попытался создать настраиваемый глобальный фильтр, но ViewData тогда недоступен.
Каков рекомендуемый способ сделать что-то подобное? Должен ли я просто оставить его, как это было сначала со всем кодом HttpContext в представлении?
Ответы
Ответ 1
Вот что я в итоге сделал. Я создал вспомогательный класс под названием 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>}
Ответ 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));
Ответ 3
Создайте частичное представление и верните его из контроллера:
LayoutViewModel.cs:
public class LayoutViewModel
{ ...
public bool ShowAdmin { get; set; }
}
LayoutController.cs:
public PartialViewResult GetAdminMenu()
{
LayoutViewModel model = new LayoutViewModel();
model.ShowAdmin = userHasPermission("Admin"); // change the code here
return PartialView("_AdminMenu", model);
}
_AdminMenu.cshtml (частичное представление):
@model DelegatePortal.ViewModels.LayoutViewModel
@if (@Model.ShowAdmin)
{
<!-- admin links here-->
}
_Layout.csthml (основной вид):
...
@Html.Action("GetAdminMenu", "Layout")