简体   繁体   中英

Building an ASP.NET MVC Master Page Menu Dynamically, Based on the current User's “Role”

I've seen some similar questions, but none that look like what I'm trying to do.

This is my current implementation w/out any security:

<div id="menucontainer">
    <ul id="menu">              
        <li><%= Html.ActionLink("Main List", "Index", "AController")%></li>
        <li><%= Html.ActionLink("Product List", "Index", "BController")%></li>
        <li><%= Html.ActionLink("Company List", "Index", "CController")%></li>
        <li><%= Html.ActionLink("User List", "Index", "DController")%></li>
    </ul>
</div>

This is fine, and the above works. I have [Authorize] Attributes setup on the Actions for CController and DController to prevent unauthorized access -- but I'd like to remove those items from the menu for users who don't have the correct Role, because when they see it and click on it and it tells them they don't have permission, they'll want it. If they don't know it's there, that's just better for everyone involved...

Something like this is ultimately the goal I'm trying to get at, but I'm looking for the more MVC Flavored aproach, where the "view" is "dumb":

<div id="menucontainer">
    <ul id="menu">              
        <li><%= Html.ActionLink("Main List", "Index", "AController")%></li>
        <li><%= Html.ActionLink("Product List", "Index", "BController")%></li>
        <% If(Role = Roles.Admin) { %>
        <li><%= Html.ActionLink("Company List", "Index", "CController")%></li>
        <li><%= Html.ActionLink("User List", "Index", "DController")%></li>
        <% } %>
    </ul>
</div>

I have done something like this:

  • use a common base class for my controllers ('layer supertype')
  • in the BaseController, override OnActionExecuted (you could also define an ActionFilter attribute for this)

Something like this:

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // build list of menu items based on user's permissions, and add it to ViewData
        IEnumerable<MenuItem> menu = BuildMenu(); 
        ViewData["Menu"] = menu;
    }

In the master page:

    <% var model = ViewData["Menu"] as IEnumerable<MenuItem>; %>
    <% Html.RenderPartial("Menu", model); %>

(Note: in reality, I have a MasterViewModel that contains among others the menu model)

没有人提到过MvcSiteMapProvider ,它可以使用NuGet轻松集成到Visual Studio项目中。

Did you hear about MvcContrib 's MenuBuilder?

If not, I suggest you take a look at it. The example project UI is a good way to start learning how to use it.

Usually I just check the role in a similar way you did and then either render a partial view with the links or just create them. Something like this using Razor syntax. I use T4MVC for actions.

@if(User.IsInRole("Admin"))
{
    <li><a href="@Url.Action(MVC.Admin.User.Index())">Users</a></li>
}

For security I use Fluent Security. Hope this helps.

Joe's solution by far was the simplest and worked for me. I have pages present in separate areas for which I need to quickly setup a menu system that reacts and works based on which area the user is present in. Also in my case there are no cross-area links in my system, so am going to next configure multiple sitemaps for the MvcSiteMapProvider .

Hope this helps anyone else looking for a simple and effective solution!

Like @SD" said, you can create a "shiny" helper that with either render the link, or not, based on your security requirement.

Here is a good read on custom helpers (towards the bottom):

understanding-html-helpers on S. Walther's blog

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM