RBAC权限模型
数据库设计
RBAC(Role-Based Access Control,基于角色的访问控制)是一种广泛使用的访问控 制模型,旨在通过角色来管理用户权限。
核心是五张表:
- user
- role
- menu
- user_role
- role_menu
一个用户可以分配多个角色,一个角色可以有多个权限,最终用户可以拥有被分配到的角色的所有权限。
数据表设计
create table sys_menu
(
menu_id bigint unsigned auto_increment comment '菜单id' primary key,
menu_name varchar(200) not null comment '菜单名称',
menu_type int not null comment '菜单类型',
parent_id bigint not null comment '父菜单id',
order_num int null comment '显示顺序',
path varchar(255) null comment '路由地址',
component varchar(255) null comment '组件路径',
perms text null comment '权限标识',
icon varchar(100) null comment '菜单图标',
frame_flag tinyint(1) default 0 null comment '是否为外链',
frame_url text null comment '外链地址',
cache_flag tinyint(1) default 0 null comment '是否缓存',
visible_flag tinyint(1) default 1 null comment '显示状态',
disabled_flag tinyint(1) default 0 null comment '禁用状态',
deleted_flag tinyint(1) default 0 not null comment '删除状态',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间'
) comment '菜单表' collate = utf8mb4_general_ci;
create table sys_role
(
role_id bigint unsigned auto_increment comment '角色id' primary key,
role_name varchar(200) null comment '角色名称',
role_key varchar(200) null comment '角色权限字符串',
role_status char null comment '角色状态(0、正常;1、禁用)'
)comment '角色表' collate = utf8mb4_general_ci;
create table sys_role_menu
(
role_id bigint unsigned not null comment '角色id',
menu_id bigint unsigned not null comment '菜单'
)comment '角色和菜单关联表' collate = utf8mb4_general_ci;
create table sys_user
(
user_id bigint auto_increment comment 'id' primary key,
user_email varchar(256) null comment '邮箱',
user_password varchar(512) null comment '密码',
union_id varchar(256) null comment '微信开放平台id',
mp_openId varchar(256) null comment '公众号openId',
user_name varchar(256) null comment '用户昵称',
user_avatar varchar(1024) null comment '用户头像',
user_profile varchar(512) null comment '用户简介',
user_role varchar(256) default 'user' not null comment '用户角色:user/admin/ban',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted_flag tinyint default 0 not null comment '是否删除'
) comment '用户' collate = utf8mb4_unicode_ci;
create table sys_user_role
(
user_id bigint unsigned not null comment '用户id',
role_id bigint unsigned not null comment '角色id'
)comment '用户和角色关联表' collate = utf8mb4_general_ci;
常见的操作
构建菜单树
返回给前端的实体类,只需要多加一个List<MenuVO> children
:
@Data
public class MenuVO {
@Schema(description = "菜单id")
private Long menuId;
// ...其余内容
private List<MenuVO> children;
}
首先查询出所有的菜单:
public BaseResponse<List<MenuVO>> queryAllMenu() {
List<MenuEntity> list = menuManager.list();
// 构建
List<MenuVO> menuVOList = buildMenuTree(list);
return ResultUtils.success(menuVOList);
}
然后去构建菜单树:
public List<MenuVO> buildMenuTree(List<MenuEntity> list) {
List<MenuVO> menuVOList = list.stream().map(menu -> BeanUtil.copyProperties(menu, MenuVO.class)).collect(Collectors.toList());
// 获取 id --> menuVO 映射
Map<Long, MenuVO> menuVOMap = menuVOList.stream().collect(Collectors.toMap(MenuVO::getMenuId, Function.identity()));
// 构建树
List<MenuVO> tree = new ArrayList<>();
for (MenuVO menuVO : menuVOList) {
if (menuVO.getParentId() == 0) {
tree.add(menuVO);
} else {
MenuVO parent = menuVOMap.get(menuVO.getParentId());
if (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(menuVO);
}
}
}
return tree;
}