# 统一资源权限控制使用说明 ## 📋 概述 采用**统一权限表** `tb_resource_permission` 来管理所有资源(新闻、课程、任务等)的访问权限,支持基于**部门**和**角色**的细粒度权限控制。 ## 🎯 设计优势 1. ✅ **统一管理**:所有资源类型的权限在一张表中管理 2. ✅ **灵活控制**:支持部门、角色、部门+角色三种授权方式 3. ✅ **细粒度**:支持读、写、执行三种权限级别 4. ✅ **易扩展**:新增资源类型只需添加类型编号 5. ✅ **高性能**:合理的索引设计,查询效率高 ## 📊 表结构 ```sql tb_resource_permission ( id VARCHAR(50) 主键 resource_type INT(4) 资源类型 resource_id VARCHAR(50) 资源ID dept_id VARCHAR(50) 部门ID(可为NULL) role_id VARCHAR(50) 角色ID(可为NULL) can_read TINYINT(1) 读权限 can_write TINYINT(1) 写权限 can_execute TINYINT(1) 执行权限 creator VARCHAR(50) 创建者 create_time TIMESTAMP 创建时间 ... ) ``` ## 🏷️ 资源类型编码 | 类型值 | 资源类型 | 说明 | |--------|----------|------| | 1 | 资源/新闻 | tb_resource | | 2 | 课程 | tb_course | | 3 | 课程章节 | tb_course_chapter | | 4 | 学习任务 | tb_learning_task | *可根据业务需要扩展更多类型* ## 🔐 权限组合说明 ### 部门和角色组合 | dept_id | role_id | 含义 | 应用场景 | |---------|---------|------|----------| | NULL | NULL | 公开 | 所有人可访问 | | 有值 | NULL | 部门限制 | 该部门所有人可访问 | | NULL | 有值 | 角色限制 | 该角色所有人可访问(跨部门) | | 有值 | 有值 | 部门+角色 | 特定部门的特定角色可访问 | ### 权限级别说明 | 权限字段 | 含义 | 典型操作 | |---------|------|----------| | can_read | 读权限 | 查看、浏览、阅读、下载 | | can_write | 写权限 | 编辑、修改、删除 | | can_execute | 执行权限 | 发布、审核、归档、推荐 | ## 💡 使用示例 ### 示例1:公开资源 ```sql -- 所有人都可以阅读的公开资源 INSERT INTO tb_resource_permission ( id, resource_type, resource_id, dept_id, role_id, can_read, can_write, can_execute, creator, create_time ) VALUES ( '1', 1, 'res_001', NULL, NULL, -- 部门和角色都为NULL表示公开 1, 0, 0, -- 只有读权限 'admin', NOW() ); ``` ### 示例2:部门限制 ```sql -- 只有"党委办公室"部门可以访问的资源 INSERT INTO tb_resource_permission ( id, resource_type, resource_id, dept_id, role_id, can_read, can_write, can_execute, creator, create_time ) VALUES ( '2', 1, 'res_002', 'dept_party_office', NULL, -- 指定部门 1, 0, 0, 'admin', NOW() ); ``` ### 示例3:角色限制(跨部门) ```sql -- 所有"管理员"角色可以编辑的课程(不限部门) INSERT INTO tb_resource_permission ( id, resource_type, resource_id, dept_id, role_id, can_read, can_write, can_execute, creator, create_time ) VALUES ( '3', 2, 'course_001', NULL, 'admin', -- 只指定角色 1, 1, 0, -- 读写权限 'admin', NOW() ); ``` ### 示例4:部门+角色组合 ```sql -- "教务处"部门的"教师"角色可以管理的课程 INSERT INTO tb_resource_permission ( id, resource_type, resource_id, dept_id, role_id, can_read, can_write, can_execute, creator, create_time ) VALUES ( '4', 2, 'course_002', 'dept_academic', 'teacher', -- 部门+角色 1, 1, 1, -- 全部权限 'admin', NOW() ); ``` ### 示例5:多个授权组合 同一个资源可以有多条权限记录: ```sql -- 示例:一个课程有多种访问权限 -- 1. 所有人可以查看 INSERT INTO tb_resource_permission VALUES ('5', 2, 'course_003', NULL, NULL, 1, 0, 0, 'admin', NOW()); -- 2. "教师"角色可以编辑 INSERT INTO tb_resource_permission VALUES ('6', 2, 'course_003', NULL, 'teacher', 1, 1, 0, 'admin', NOW()); -- 3. "教务处"的"管理员"可以发布 INSERT INTO tb_resource_permission VALUES ('7', 2, 'course_003', 'dept_academic', 'admin', 1, 1, 1, 'admin', NOW()); ``` ## 🔍 权限查询 ### 查询1:检查用户对资源的访问权限 ```sql -- 检查用户是否可以访问某个资源 -- 假设:用户部门='dept_001',角色='teacher',资源类型=2,资源ID='course_001' SELECT MAX(can_read) as has_read, MAX(can_write) as has_write, MAX(can_execute) as has_execute FROM tb_resource_permission WHERE resource_type = 2 AND resource_id = 'course_001' AND deleted = 0 AND ( -- 公开资源 (dept_id IS NULL AND role_id IS NULL) OR -- 部门匹配 (dept_id = 'dept_001' AND role_id IS NULL) OR -- 角色匹配 (dept_id IS NULL AND role_id = 'teacher') OR -- 部门+角色匹配 (dept_id = 'dept_001' AND role_id = 'teacher') ); ``` ### 查询2:获取用户可访问的资源列表 ```sql -- 获取用户可以访问的所有课程 -- 假设:用户部门='dept_001',角色列表=['teacher', 'user'] SELECT DISTINCT rp.resource_id, c.* FROM tb_resource_permission rp INNER JOIN tb_course c ON c.course_id = rp.resource_id WHERE rp.resource_type = 2 AND rp.can_read = 1 AND rp.deleted = 0 AND ( (rp.dept_id IS NULL AND rp.role_id IS NULL) OR (rp.dept_id = 'dept_001' AND rp.role_id IS NULL) OR (rp.dept_id IS NULL AND rp.role_id IN ('teacher', 'user')) OR (rp.dept_id = 'dept_001' AND rp.role_id IN ('teacher', 'user')) ) ORDER BY c.create_time DESC; ``` ### 查询3:获取资源的所有权限配置 ```sql -- 查看某个资源配置了哪些权限 SELECT rp.*, d.name as dept_name, r.name as role_name FROM tb_resource_permission rp LEFT JOIN tb_sys_dept d ON d.dept_id = rp.dept_id LEFT JOIN tb_sys_role r ON r.role_id = rp.role_id WHERE rp.resource_type = 1 AND rp.resource_id = 'res_001' AND rp.deleted = 0; ``` ## 🎨 业务场景实现 ### 场景1:新闻资源的分级查看 ```sql -- 1. 公开新闻:所有人可查看 INSERT INTO tb_resource_permission VALUES (UUID(), 1, 'news_public', NULL, NULL, 1, 0, 0, 'admin', NOW()); -- 2. 内部新闻:全体员工可查看 INSERT INTO tb_resource_permission VALUES (UUID(), 1, 'news_internal', NULL, 'employee', 1, 0, 0, 'admin', NOW()); -- 3. 机密新闻:只有党委办公室可查看 INSERT INTO tb_resource_permission VALUES (UUID(), 1, 'news_confidential', 'dept_party', NULL, 1, 0, 0, 'admin', NOW()); ``` ### 场景2:课程权限分配 ```sql -- 1. 所有学生可以学习 INSERT INTO tb_resource_permission VALUES (UUID(), 2, 'course_101', NULL, 'student', 1, 0, 0, 'admin', NOW()); -- 2. 授课教师可以编辑 INSERT INTO tb_resource_permission VALUES (UUID(), 2, 'course_101', NULL, 'teacher', 1, 1, 0, 'admin', NOW()); -- 3. 教务处管理员可以发布 INSERT INTO tb_resource_permission VALUES (UUID(), 2, 'course_101', 'dept_academic', 'admin', 1, 1, 1, 'admin', NOW()); ``` ### 场景3:学习任务的部门分配 ```sql -- 为不同部门分配不同的学习任务 -- 党委办公室的任务 INSERT INTO tb_resource_permission VALUES (UUID(), 4, 'task_party', 'dept_party', NULL, 1, 0, 1, 'admin', NOW()); -- 教务处的任务 INSERT INTO tb_resource_permission VALUES (UUID(), 4, 'task_academic', 'dept_academic', NULL, 1, 0, 1, 'admin', NOW()); ``` ## 📝 Java代码示例 ### 权限检查工具类 ```java public class ResourcePermissionChecker { /** * 检查用户是否有资源访问权限 */ public boolean hasPermission(String userId, int resourceType, String resourceId, PermissionType type) { // 1. 获取用户的部门和角色 UserInfo user = getUserInfo(userId); List roleIds = user.getRoleIds(); String deptId = user.getDeptId(); // 2. 查询权限 List permissions = permissionMapper.selectList( new QueryWrapper() .eq("resource_type", resourceType) .eq("resource_id", resourceId) .eq("deleted", 0) .and(wrapper -> wrapper // 公开 .or(w -> w.isNull("dept_id").isNull("role_id")) // 部门匹配 .or(w -> w.eq("dept_id", deptId).isNull("role_id")) // 角色匹配 .or(w -> w.isNull("dept_id").in("role_id", roleIds)) // 部门+角色匹配 .or(w -> w.eq("dept_id", deptId).in("role_id", roleIds)) ) ); // 3. 判断权限 for (ResourcePermission perm : permissions) { switch (type) { case READ: if (perm.getCanRead()) return true; break; case WRITE: if (perm.getCanWrite()) return true; break; case EXECUTE: if (perm.getCanExecute()) return true; break; } } return false; } /** * 获取用户可访问的资源ID列表 */ public List getAccessibleResources(String userId, int resourceType) { UserInfo user = getUserInfo(userId); // ... 类似逻辑 return resourceIds; } } ``` ### 权限注解 ```java @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RequirePermission { ResourceType resourceType(); PermissionType permission() default PermissionType.READ; } // 使用示例 @RequirePermission(resourceType = ResourceType.COURSE, permission = PermissionType.WRITE) public void updateCourse(String courseId, CourseDTO dto) { // ... } ``` ## ⚠️ 注意事项 1. **NULL值处理**:dept_id 和 role_id 为 NULL 时有特殊含义,不能用空字符串代替 2. **权限优先级**:查询时使用 MAX() 聚合,任一条记录授权即有权限 3. **索引优化**:已创建组合索引 `idx_resource`,确保查询性能 4. **软删除**:使用 deleted 字段,避免物理删除导致的问题 5. **唯一约束**:`uk_resource_dept_role` 防止重复配置,包含 deleted 字段支持重复添加 ## 🔄 权限变更场景 ### 场景1:资源从公开改为部门限制 ```sql -- 1. 删除原公开权限 UPDATE tb_resource_permission SET deleted = 1, delete_time = NOW() WHERE resource_type = 1 AND resource_id = 'res_001' AND dept_id IS NULL AND role_id IS NULL; -- 2. 添加部门限制 INSERT INTO tb_resource_permission VALUES (UUID(), 1, 'res_001', 'dept_target', NULL, 1, 0, 0, 'admin', NOW()); ``` ### 场景2:提升用户权限(从只读到读写) ```sql -- 更新权限级别 UPDATE tb_resource_permission SET can_write = 1, updater = 'admin', update_time = NOW() WHERE resource_type = 2 AND resource_id = 'course_001' AND role_id = 'teacher'; ``` ## 📈 性能优化建议 1. **合理使用索引**:已创建的索引包括 `idx_resource`、`idx_dept`、`idx_role` 2. **缓存策略**:对频繁访问的资源权限进行Redis缓存 3. **批量查询**:使用 IN 子句批量查询多个资源的权限 4. **避免全表扫描**:查询时务必带上 resource_type 和 resource_id ## 🔗 相关表说明 - `tb_sys_dept`: 部门表 - `tb_sys_role`: 角色表 - `tb_sys_user_dept_role`: 用户-部门-角色关联表 - `tb_resource`: 资源表 - `tb_course`: 课程表 - `tb_learning_task`: 学习任务表