代码未动,设计先行。为什么你的权限系统扩展性差?往往是因为数据库设计不合理。本文将深入剖析 RBAC 模型的底层逻辑,设计用户、角色、菜单及其关联表,并详细讲解 role_key、perms、hidden 等关键字段的设计意图。
前置文章:
从零开始:在阿里云 Ubuntu 服务器部署 Node+Express 接口(一)
阿里云域名解析 + Nginx 反向代理 + HTTPS 全流程:从 IP 访问到加密域名的完整配置(二)
后端代码部署到服务器,服务器配置数据库,pm2进程管理发布(四)
一、 RBAC 模型核心逻辑
在传统的权限设计中,我们直接把权限赋给用户。但在企业中,员工入职离职频繁,逐个配置权限非常痛苦。 RBAC 的核心思想是:
- 用户 (User) 归属于 角色 (Role) 。
- 角色 (Role) 拥有 菜单/权限 (Menu) 。
- 用户通过角色,间接拥有了权限。
这样的好处是:当来了一个新员工,我只需要把他关联到“财务”角色,他就自动拥有了财务相关的所有报表查看权限。
二、 数据库表结构设计 (SQL)
我们需要 5 张核心表来支撑这个系统:
- sys_users:用户表 (已在上一篇创建)
- sys_roles:角色表 (身份的象征)
- sys_menus:菜单权限表 (资源的集合)
- sys_role_menus:角色-菜单关联表 (权限的分配)
- sys_oper_log:操作日志表 (安全审计)
1. 角色表 (sys_roles)
CREATE TABLE `sys_roles` (
`id` int NOT NULL AUTO_INCREMENT,
`role_name` varchar(30) NOT NULL COMMENT '角色名称 (如:超级管理员)',
`role_key` varchar(100) NOT NULL COMMENT '权限字符 (如:admin, common)',
`sort` int DEFAULT 0 COMMENT '显示顺序',
`status` tinyint(1) DEFAULT 1 COMMENT '状态 (1正常 0停用)',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色信息表';
- 设计细节 role_key:这是给后端代码看的。比如我们在代码里写 if (user.roleKey === 'admin') 来给予最高权限(上帝模式)。前端也可以用它来判断是否显示某些非按钮类的组件。
菜单权限表 (sys_menus) —— 最核心的表
这张表不仅存左侧菜单,还存页面内的按钮。
CREATE TABLE `sys_menus` (
`id` int NOT NULL AUTO_INCREMENT,
`parent_id` int DEFAULT 0 COMMENT '父菜单ID',
`menu_name` varchar(50) NOT NULL COMMENT '菜单名称',
`path` varchar(200) DEFAULT '' COMMENT '路由地址',
`component` varchar(255) DEFAULT NULL COMMENT '组件路径 (views下的路径)',
`perms` varchar(100) DEFAULT NULL COMMENT '权限标识 (如 system:user:add)',
`icon` varchar(100) DEFAULT '#' COMMENT '图标',
`type` char(1) DEFAULT 'M' COMMENT '类型 (M目录 C菜单 F按钮)',
`hidden` tinyint(1) DEFAULT 0 COMMENT '可见性 (0显示 1隐藏)',
`no_cache` tinyint(1) DEFAULT 0 COMMENT '是否缓存 (0缓存 1不缓存)',
`sort` int DEFAULT 0 COMMENT '排序',
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表';
-
type:
- M (Directory) :目录。如“系统管理”,它没有组件路径,点击展开子菜单。
- C (Menu) :菜单。如“用户管理”,点击后跳转页面,有 component 路径。
- F (Button) :按钮。如“新增用户”,它不显示在侧边栏,但需要存储 perms 供前端 v-hasPermi 指令使用。
-
hidden:
- 默认为 0 (显示)。
- 设为 1 (隐藏) 时,侧边栏看不见,但路由依然注册。适用于“用户详情页”这种不需要在菜单栏占位的页面。
. 角色-菜单关联表 (sys_role_menus)
CREATE TABLE `sys_role_menus` (
`role_id` int NOT NULL,
`menu_id` int NOT NULL,
PRIMARY KEY (`role_id`, `menu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色菜单关联表';
4. 操作日志表 (sys_oper_log)
用于记录谁在什么时候干了什么,方便追溯。
CREATE TABLE `sys_oper_log` (
`oper_id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(50) DEFAULT '' COMMENT '模块标题',
`business_type` int(2) DEFAULT 0 COMMENT '业务类型 (1新增 2修改 3删除)',
`oper_name` varchar(50) DEFAULT '' COMMENT '操作人员',
`oper_url` varchar(255) DEFAULT '' COMMENT '请求URL',
`oper_ip` varchar(128) DEFAULT '' COMMENT 'IP地址',
`json_result` text COMMENT '返回结果',
`status` int(1) DEFAULT 0 COMMENT '操作状态',
`error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息',
`oper_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`oper_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表';
四、 总结
这一篇我们完成了 RBAC 系统最底层的数据建模。
- sys_menus 表通过 type 和 hidden 字段灵活支持了目录、菜单、按钮和隐藏路由。
- 通过 sys_role_menus 实现了权限的解耦。
有了这些数据,下一篇我们将挑战全栈开发中最复杂的逻辑之一:如何在后端根据权限递归生成动态路由树,并在前端动态渲染侧边栏。
具备完整功能后台管理系统的代码仓库:
感谢大家的star
前端:前端
后端:后端