档案管理系统RBAC权限模型设计与实操落地指南
一、数据库模型设计
构建档案软件的权限体系,首选RBAC(基于角色的访问控制)模型。为了满足档案管理中常见的“部门隔离”和“密级控制”需求,我们需要在标准RBAC基础上扩展数据权限字段。以下是基于MySQL 8.0的完整建表语句,可直接复制执行。
```sql -- 1. 用户表 CREATE TABLE `sys_user` ( `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID', `dept_id` bigint(20) DEFAULT NULL COMMENT '归属部门ID', `user_name` varchar(30) NOT NULL COMMENT '用户账号', `real_name` varchar(30) DEFAULT NULL COMMENT '用户姓名', `password` varchar(100) DEFAULT NULL COMMENT '密码', `status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)', PRIMARY KEY (`user_id`), UNIQUE KEY `uk_user_name` (`user_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 2. 角色表(扩展数据范围字段) CREATE TABLE `sys_role` ( `role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID', `role_name` varchar(30) NOT NULL COMMENT '角色名称', `role_key` varchar(100) NOT NULL COMMENT '角色权限字符串', `data_scope` char(1) DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定义数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限)', `status` char(1) DEFAULT '0' COMMENT '角色状态(0正常 1停用)', PRIMARY KEY (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; -- 3. 菜单权限表 CREATE TABLE `sys_menu` ( `menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID', `menu_name` varchar(50) NOT NULL COMMENT '菜单名称', `parent_id` bigint(20) DEFAULT '0' COMMENT '父菜单ID', `order_num` int(4) DEFAULT '0' COMMENT '显示顺序', `perms` varchar(100) DEFAULT NULL COMMENT '权限标识(如 archive:file:add)', `menu_type` char(1) DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)', `visible` char(1) DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)', PRIMARY KEY (`menu_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表'; -- 4. 用户-角色关联表 CREATE TABLE `sys_user_role` ( `user_id` bigint(20) NOT NULL COMMENT '用户ID', `role_id` bigint(20) NOT NULL COMMENT '角色ID', PRIMARY KEY (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和角色关联表'; -- 5. 角色-菜单关联表 CREATE TABLE `sys_role_menu` ( `role_id` bigint(20) NOT NULL COMMENT '角色ID', `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', PRIMARY KEY (`role_id`,`menu_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和菜单关联表'; ```二、初始化基础权限数据
表结构建立后,需要初始化一套基础的档案管理权限数据。我们将创建一个“档案管理员”角色,拥有全部权限;一个“普通职员”角色,仅拥有上传和查看自己档案的权限。执行以下SQL脚本完成数据初始化。
```sql -- 插入部门 INSERT INTO `sys_dept` VALUES (100, 0, '总部', 0, '0'); -- 插入用户(密码假设已加密为 admin123) INSERT INTO `sys_user` VALUES (1, 100, 'admin', '系统管理员', '$2a$10$7JB720yubVSZvUI0rEqT/.VqGO0THJ8wXtz/r5J.8j/2/U/u/jj2', '0'); INSERT INTO `sys_user` VALUES (2, 100, 'zhangsan', '张三', '$2a$10$7JB720yubVSZvUI0rEqT/.VqGO0THJ8wXtz/r5J.8j/2/U/u/jj2', '0'); -- 插入角色 -- 管理员:data_scope=1 (全部数据) INSERT INTO `sys_role` VALUES (1, '档案管理员', 'admin', '1', '0'); -- 普通职员:data_scope=5 (仅本人数据) INSERT INTO `sys_role` VALUES (2, '普通职员', 'common', '5', '0'); -- 分配用户角色 INSERT INTO `sys_user_role` VALUES (1, 1); INSERT INTO `sys_user_role` VALUES (2, 2); -- 插入菜单权限 INSERT INTO `sys_menu` VALUES (1, '档案管理', 0, 1, '', 'M', '0'); INSERT INTO `sys_menu` VALUES (2, '档案列表', 1, 1, 'archive:file:list', 'C', '0'); INSERT INTO `sys_menu` VALUES (3, '档案上传', 1, 2, 'archive:file:add', 'F', '0'); INSERT INTO `sys_menu` VALUES (4, '档案下载', 1, 3, 'archive:file:download', 'F', '0'); INSERT INTO `sys_menu` VALUES (5, '档案删除', 1, 4, 'archive:file:remove', 'F', '0'); -- 为档案管理员分配所有权限 INSERT INTO `sys_role_menu` SELECT 1, menu_id FROM sys_menu; -- 为普通职员分配查看和上传权限 INSERT INTO `sys_role_menu` VALUES (2, 1); INSERT INTO `sys_role_menu` VALUES (2, 2); INSERT INTO `sys_role_menu` VALUES (2, 3); ```三、后端功能权限校验逻辑
后端校验的核心是判断当前用户是否拥有访问特定API所需的权限标识。以下以Python (Flask + SQLAlchemy) 为例,展示完整的校验逻辑。其他语言(Java/Go/Node.js)逻辑一致,仅需调整SQL查询方式。
1. 获取用户权限列表的辅助函数
在用户登录成功后,需将用户的权限字符串缓存到Redis或Session中,避免每次请求都查库。以下是获取权限列表的查询逻辑:
```python def get_user_permissions(user_id): SQL逻辑:通过用户表 -> 关联角色表 -> 关联菜单表 -> 获取权限标识 sql = """ SELECT DISTINCT m.perms FROM sys_user u LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id LEFT JOIN sys_role r ON ur.role_id = r.role_id LEFT JOIN sys_role_menu rm ON r.role_id = rm.role_id LEFT JOIN sys_menu m ON rm.menu_id = m.menu_id WHERE u.user_id = :user_id AND u.status = '0' AND r.status = '0' AND m.perms IS NOT NULL """ 假设使用数据库连接执行查询 results = db.session.execute(sql, {'user_id': user_id}).fetchall() 提取权限字符串并存入集合,方便O(1)查询 permission_set = {row[0] for row in results} return permission_set ```2. 权限校验装饰器
创建一个装饰器,用于保护需要特定权限的API接口。例如,只有拥有 archive:file:remove 权限的用户才能调用删除接口。
3. 应用校验到接口
在路由上直接使用装饰器,实现零侵入式权限控制。
```python @app.route('/api/archive/file/四、数据权限(行级)实操落地

档案软件中,不仅要控制“能不能点按钮”,还要控制“能看到哪些数据”。例如,普通职员只能看到自己上传的档案。这需要在SQL查询层面动态拼接 WHERE 条件。
1. 构建数据权限SQL片段
我们需要一个函数,根据用户角色的 data_scope 字段,生成对应的SQL过滤条件。假设档案表为 sys_archive,其中包含 dept_id 和 create_by 字段。
五、前端按钮级权限控制
后端拦截了API请求,但为了用户体验,前端也应直接隐藏无权操作的按钮。以下是Vue.js的实现方案,React逻辑类似。
1. 配置权限指令
在Vue项目的 main.js 或指令文件中,注册一个全局指令 v-hasPermi。
2. 在页面模板中使用
在列表页面的操作列中,对删除、下载按钮应用该指令。如果当前用户没有对应权限,按钮将不会渲染。
```html通过以上五个步骤,从数据库设计到前端控制,完成了一套完整的、可落地的档案软件操作权限系统。开发者只需根据实际业务调整具体的权限标识字符串(如 archive:file:add)即可直接复用。