node全栈系列(六)(RBAC实战)-五张表搞定企业级权限设计

89 阅读4分钟

代码未动,设计先行。为什么你的权限系统扩展性差?往往是因为数据库设计不合理。本文将深入剖析 RBAC 模型的底层逻辑,设计用户、角色、菜单及其关联表,并详细讲解 role_key、perms、hidden 等关键字段的设计意图。

前置文章:

从零开始:在阿里云 Ubuntu 服务器部署 Node+Express 接口(一)

阿里云域名解析 + Nginx 反向代理 + HTTPS 全流程:从 IP 访问到加密域名的完整配置(二)

Node+Express+MySQL 实现注册功能(三)

后端代码部署到服务器,服务器配置数据库,pm2进程管理发布(四)

彻底搞懂 JWT 登录认证与路由守卫(五)

一、 RBAC 模型核心逻辑

在传统的权限设计中,我们直接把权限赋给用户。但在企业中,员工入职离职频繁,逐个配置权限非常痛苦。 RBAC 的核心思想是

  1. 用户 (User)  归属于 角色 (Role)
  2. 角色 (Role)  拥有 菜单/权限 (Menu)
  3. 用户通过角色,间接拥有了权限。

这样的好处是:当来了一个新员工,我只需要把他关联到“财务”角色,他就自动拥有了财务相关的所有报表查看权限。

二、 数据库表结构设计 (SQL)

我们需要 5 张核心表来支撑这个系统:

  1. sys_users:用户表 (已在上一篇创建)
  2. sys_roles:角色表 (身份的象征)
  3. sys_menus:菜单权限表 (资源的集合)
  4. sys_role_menus:角色-菜单关联表 (权限的分配)
  5. 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

前端:前端

后端:后端