Files
schoolNews/schoolNewsServ/.bin/mysql/sql/权限控制使用说明.md
2025-10-15 10:39:51 +08:00

396 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 统一资源权限控制使用说明
## 📋 概述
采用**统一权限表** `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<String> roleIds = user.getRoleIds();
String deptId = user.getDeptId();
// 2. 查询权限
List<ResourcePermission> permissions = permissionMapper.selectList(
new QueryWrapper<ResourcePermission>()
.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<String> 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`: 学习任务表