ASP.Net MVC Hide/Show Menu Items Based On Security

Here is what I ended up doing. I created a helper class called MenuSecurity with static boolean properties for each menu item showing which items should be visible. Each property looked like this

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

I then tidied up my menu partial view to look like this

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

General advice about roles

The way I have done this is to create a custom principal and to store the extra required information in there. In your example, this would at least include the roles for the user. That way you avoid making lots of extra trips to the user store (which is likely a SQL database).

Have a look a this question of mine in which I give the code which I am using successfully: Is this Custom Principal in Base Controller ASP.NET MVC 3 terribly inefficient?

Note that I am storing the custom principal in the cache rather than in the session (just being paranoid about session hijacking).

I like this approach as it is very extensible. For example, I have since extended this to expose Facebook credentials for when the user logs in via Facebook.

Just remember that if you are caching data you need to remember to update it when it changes!

Answer to your question

Just to add, in your specific case, you should probably store this extra information in a ViewModel and then your view would say things like:

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

with the ViewModel Code saying something like:

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

I actually tend to take this one step further and create a ReportsLink in my ViewModel and set it to contain the link if the user is authorised or to be an empty string if they are not. Then the view just says:

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

In that case the pertinent part of the ViewModel might be like this:

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