MVC4 Bootstrap示例中基于角色的导航显示

5
在 Bootstrap 示例项目中,如何根据角色有条件地显示菜单项?我考虑采取以下步骤:
1. 实现INavigatonRouteFilter - 只需实现shouldRemove(Route navigationRoutes)方法 - 通过获取路由的默认控制器/操作并查看用户是否获得授权来实现。 2. 在配置NavigationRoutes后调用NavigationRoutes.Filters.Add(myAuthorizationFilter)。
这种方法存在两个问题:
1. 除非添加一堆有条件的语句来检查Controller的名称,否则我不知道如何执行第一步。 2. 如果有很多过滤器或以后需要更多的模块化,似乎这样做会使 NavigationRoutes.Filters 很难处理。
如果可能的话,我想使用Bootstrap示例中提供的内容来实现基于授权的导航菜单显示。使用INavigationRouteFilter似乎是最自然的方式。

我想做同样的事情,你成功地完成了吗? - Cybercop
@Biplov13 不,我还没有,但我正在努力。当我想到什么东西时,我会把它作为答案发布,但我希望其他人已经做了这个,这样我就感觉自己在做“正确”的事情。 - tacos_tacos_tacos
1个回答

5

对于那些寻求答案或至少寻求快速解决方案的人来说,以下是我在5分钟内想出的方案,请注意我并没有考虑可能带来的任何副作用。

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

您可以在调用FilterRoute()时完成所有筛选,也可以添加更多扩展方法来节省一些字符。

我想到了.RequireRole("Adiministrators"); 这将依次调用WebSecurity.RequireRoles() (或HttpContext.Current.User.IsInRole())等。

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

BootstrapAuthorizationFilter是实现了INavigationRouteFilter接口的一个类,它在其ShouldRemove()方法中调用func()。

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

显然这并不是什么高级的东西,我也不确定是否会在生产环境中使用它。 但我认为它足够简单且有效(根据我测试的情况)。 话虽如此,我希望新的路由功能能尽快发布 :)


这太棒了。但我无法弄清如何修改以适用于子路由。 - friggle
2
明白了。复制FilterRoute方法为FilterChildRoute,只需将“currentRoute = builder._parent.Children.Last()”修改即可。然后修改GetRoutesForCurrentRequest,在“if (filter.ShouldRemove(route)) { ... }”后插入“foreach(var childRoute in route.Children.ToArray()) { if (filter.ShouldRemove(childRoute) { route.Children.Remove(childRoute); } }”。最后确保FilterChildRoute()直接链接到要过滤的AddChildRoute()上即可。 - friggle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接