Search code examples
asp.net-mvcasp.net-mvc-4twitter-bootstrapsystem.web.routing

Role-based navigation display in MVC4 Bootstrap Sample


How are you supposed to conditionally display menu items based on roles in the Bootstrap Sample project? I was thinking of doing the following

  1. Implement INavigatonRouteFilter - really just implementing the shouldRemove(Route navigationRoutes) method - by getting the default controller/action for the route and seeing if the user is authorized
  2. Call NavigationRoutes.Filters.Add(myAuthorizationFilter) after configuring the NavigationRoutes in App_Start

There are two problems I see with this approach:

  1. I don't actually know how to do the first step unless I add in a bunch of conditional statements to check for Controller's name explicitly
  2. This seems like it could make NavigationRoutes.Filters very hard to deal with once there are a lot of filters or a desire for more modularity later on

I don't know that I've explained the problem clearly enough, but basically I want to use what is provided in the Bootstrap sample to implement authorization-based navigation menu display if at all possible. Using INavigationRouteFilter just seemed like the most natural way to do so.


Solution

  • For those looking for an answer or at least a quick fix. Here's what I've come up with after 5 minutes and I most certainly haven't though about any side effects this may have.

    routes.MapNavigationRoute<HomeController>("Index", c => c.Index())
                .FilterRoute(() => !WebSecurity.IsAuthenticated);
    

    You can either do all your filtering in your call to FilterRoute() or you can add more extension methods to save you some characters.

    I'm thinking of .RequireRole("Adiministrators"); that calls WebSecurity.RequireRoles() in turn (or HttpContext.Current.User.IsInRole()) etc.

    public static NavigationRouteBuilder FilterRoute(this NavigationRouteBuilder builder, Func<bool> func)
        {
            var currentRoute = builder._parent;
    
            NavigationRoutes.Filters.Add(new BootstrapAuthorizationFilter(builder, x => 
            {
                if (x == currentRoute)
                    return func();
                else
                    return false;
            }));
    
            return builder;
        }
    

    and BootstrapAuthorizationFilter is just a class implementing INavigationRouteFilter that calls func() in its ShouldRemove() method

    public class BootstrapAuthorizationFilter : INavigationRouteFilter
    {
        private NavigationRouteBuilder builder;
        private Func<NamedRoute, bool> func;
    
        public BootstrapAuthorizationFilter(NavigationRouteBuilder builder, Func<NamedRoute, bool> func)
        {
            this.builder = builder;
            this.func = func;
        }
    
        public bool ShouldRemove(Route navigationRoutes)
        {
            if (navigationRoutes is NamedRoute)
                return func(navigationRoutes as NamedRoute);
    
            return false;
        }
    }
    

    Clearly nothing fancy and I'm not sure if I'd use it in production. But I think is simple enough and works (for the cases I tested). Having said that, I hope the new routing functionality is going to be released soon :)