一、首先我们需要有三张基础表
1.用户表(Account):包含用户id、登录名、密码、手机号、邮箱、创建时间、账户状态(停用或启用)、备注。
2.角色表(Roles):不同的角色代表了不同的权限, 字段:角色id、角色名、角色信息(不是必要)、角色状态(停用或启用)、备注。
3.菜单表(Menus):不同的菜单进入的页面具有不同的功能,字段:菜单id、菜单名称、跳转url、是否菜单(因为有些地方可能会把添加模块作为一个单独的页面,而又不希望其直接出现在系统的侧边栏里面,当然我一般使用弹框做添加数据)、菜单icon图标(不必要)、备注、二级菜单id。
二.有了三张基础表后,我们需要思考三张表之间有怎样的关系。
用户——角色——菜单:
1、用户面对角色:一个用户可以有多个角色,一个角色也可以有多个用户,但一般我们只分配一个角色。所以也可以在用户表中再加一个角色id,不过我这里设计的是一个用户可以有多个角色的情况,所以是多对多的。
那么就需要有一个用户角色关联表(AccountRoles):关联id、用户id、角色id
2、角色面对菜单:一个角色可以有多个菜单,一个菜单也可以被多个角色拥有。所以也是多对多的关系。
那么就要有角色菜单关联表(RoleMenus):关联id、角色id、菜单id
到这里数据库的设计就完成了。
总体的关系图就是这样的
三、模拟一个场景
在登录成功之后,我们可以根据用户的id去查询它对应的角色,再查出角色对应的菜单,然后在页面渲染菜单集合。就实现了不同用户进入系统得到的是不同的菜单。
首先用户不直接面对菜单,而是面对角色,而角色拥有菜单,这样用户就间接的拥有了菜单。并且如果我们想给用户新增一个菜单时,只需要给对应的角色多分配一个菜单就可以了。同时如果用户在地址栏强行改url跳转时,也可以通过过滤器对其进行验证,判断是否拥有此菜单。
四、一级菜单和二级菜单的实现
然后重点说一下一级菜单和二级菜单怎么区分,以及怎么把二级菜单归属到一级菜单中:
首先我们知道,一级菜单是直接显示在侧边栏的,而二级则在一级菜单的下面,如:
那么如果数据库中只有二级菜单,而这些二级菜单都没有所属的一级菜单,是无法显示出来的。但一级菜单下面却可以不需要一定有二级菜单。
回过来看数据库,我们最后有一个pid,用来判断是否是一级还是二级,拟定0为一级,那么不为0的都为二级,那如何判断二级是属于哪个一级下面的呢,这时我们可以把二级的pid设定为一级菜单的MenuID,如图,账户管理、角色管理、菜单管理的pid都是10,而10是一级菜单权限管理的MenuID。
然后可以看我的数据
用户表
用户有一个角色,这个角色是超级管理员
这个角色对应的菜单
我们需要渲染在页面上的时候可以封装一个类
public class ResultMenu
{
public string MenuName { get; set; }
public string MenuUrl { get; set; }
public string MenuRemark { get; set; }
public List<ResultMenu> SubMenu { get; set; }
}
递归获取菜单
protected List<ResultMenu> GetMenu(List<Menu> menus)
{
List<ResultMenu> resultMenus = new List<ResultMenu>();
// 顶级菜单
var pMenus = menus.Where(x => x.Pid == 0).ToList();
foreach (var itemMenu in pMenus)
{
ResultMenu resultMenu = new ResultMenu
{
MenuName = itemMenu.Name,
MenuRemark = itemMenu.Remark,
MenuUrl = itemMenu.Url,
SubMenu = GetChildrenMenu(itemMenu.MenuId, menus)
};
resultMenus.Add(resultMenu);
}
return resultMenus;
}
/// <summary>
/// 获取子菜单
/// </summary>
/// <param name="mid">菜单id</param>
/// <param name="menus">角色拥有的所有菜单</param>
/// <returns></returns>
protected List<ResultMenu> GetChildrenMenu(int mid,List<Menu> menus)
{
List<ResultMenu> resultMenus = new List<ResultMenu>();
// 获取子菜单
var childrenMenus = menus.Where(x => x.Pid == mid).ToList();
foreach (var itemMenu in childrenMenus)
{
ResultMenu resultMenu = new ResultMenu
{
MenuName = itemMenu.Name,
MenuRemark = itemMenu.Remark,
MenuUrl = itemMenu.Url,
SubMenu = GetChildrenMenu(itemMenu.MenuId, menus)
};
resultMenus.Add(resultMenu);
}
return resultMenus;
}
最后得到这样的数据格式
需要源码的可以加.net core学习交流群:831181779,在群里@群主即可