Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 241
tacos_tacos_tacos Avatar asked Jun 01 '13 21:06

tacos_tacos_tacos


1 Answers

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 :)

like image 73
Brunner Avatar answered Sep 21 '22 02:09

Brunner