Appearance
09_用户与账号管理 API 设计(学生/老师/学校管理员/平台管理员)
目标:提供统一的用户与账号管理接口,满足"平台管理员 > 学校管理员 > 老师 > 学生"的分级权限要求。
- 学生:不能创建/删除/修改账号(仅允许补充个人展示信息如头像、真实姓名)。
- 老师:管理自己班级学生(增删班级成员、重置学生密码、查看学生信息),不能越权到其他班级或学校。
- 学校管理员:管理本校老师与学生账号(创建、禁用、启用、重置密码、分配班级、指派班主任/授课老师)。
- 平台管理员:管理全平台账号及学校、跨校迁移等高级操作。
1. 角色与术语
角色(与
app/models/user.py对齐):student:学生teacher:教师school_admin:学校管理员platform_admin:平台管理员
组织对象:
schools:学校classes:教学班(隶属学校)
关系对象:
class_members:学生-班级关系class_teachers:教师-班级关系
2. 资源与命名
- 主资源:
users - 子资源:
/users/{user_id}/profile:用户可维护的少量自我信息(头像、真实姓名)/schools/{school_id}/users:作用域内的用户管理(学校管理员)- 班级与学校管理接口已迁移:详见《13_School_API》《14_Class_API》
2.1 学生个人成就(新增)
- GET
/users/{user_id}/achievements- 说明:统计学生个人成就
- 口径:
total_assignments_submitted:该学生提交过的不同作业数量(按 assignment 去重)completed_courses:对该学生所在班级发布的某课程,若该课程所有已发布作业均已提交,则该课程计为完成
- 权限:学生本人/管理员可查(老师权限可按需细化)
- 响应示例:json
{ "total_assignments_submitted": 23, "completed_courses": 4 }
3. 权限原则(概览)
学生(student):
- 仅能读自己的信息
- 不可创建/删除/修改账号
- 可编辑
real_name、avatar_url(若系统策略允许) - 上级为教师或学校管理员(
parent_user_id指向创建者)
老师(teacher):
- 可管理自己任教班级内学生(添加/移除班级成员、重置学生密码、查看学生信息)
- 不可在非任教班级或其他学校执行写操作
- 上级为学校管理员(
parent_user_id指向学校管理员)
学校管理员(school_admin):
- 可在本学校范围创建/更新/禁用老师与学生账号
- 可为老师/学生分配班级
- 可重置密码
- 不可跨校操作
- 不可授予平台管理员角色
- 上级为平台管理员(
parent_user_id指向平台管理员)
平台管理员(platform_admin):
- 可管理所有学校与所有用户
- 可执行跨校迁移、删除账号、角色调整
- 可授予/撤销学校管理员角色
- 可管理学校信息
- 没有上级(
parent_user_id为null)
4. 权限矩阵
| 资源/操作 | 匿名 | 学生 | 老师 | 学校管理员 | 平台管理员 |
|---|---|---|---|---|---|
列表用户 /users | × | × | 限本班学生 | 本校范围 | 全平台 |
获取用户 /users/{id} | × | 仅本人 | 本班学生 | 本校用户 | 全平台 |
创建学生 /schools/{id}/users:student | × | × | × | ✓(本校) | ✓(任意校) |
创建老师 /schools/{id}/users:teacher | × | × | × | ✓(本校) | ✓(任意校) |
创建学校管理员 /schools/{id}/users:school_admin | × | × | × | × | ✓(任意校) |
| 更新用户基础字段 | × | 仅本人profile | 本班学生受限 | 本校用户 | 全平台 |
重置密码 /users/{id}:reset_password | × | × | 本班学生 | 本校用户 | 全平台 |
禁用/启用 /users/{id}:status | × | × | × | 本校用户 | 全平台 |
删除账号 /users/{id} | × | × | × | 本校用户(可配置仅停用) | 全平台 |
班级成员管理 /classes/{id}/members | × | × | ✓(任教班) | 本校 | 全平台 |
班级教师管理 /classes/{id}/teachers | × | × | 仅本人查看/退出 | 本校 | 全平台 |
学校管理 /schools | × | × | × | 仅查看本校 | 全平台 |
注:实际实现中,删除账号通常建议采用"软删除/停用(disabled)"以保留历史关联数据。
5. 数据模型(对齐现有模型)
users:id, username, password_hash, role, school_id, parent_user_id?, real_name?, avatar_url?, created_atschools:id, name, region?, logo_url?, created_atclasses:id, school_id, name, edu_year?, created_atclass_members:id, class_id, user_id, joined_atclass_teachers:id, class_id, teacher_id, role
扩展建议:
users.disabled: bool(是否停用)users.require_password_reset: bool(下次登录需改密)
上级关系说明:
parent_user_id表示用户的直接上级账号ID,用于权限继承和管理关系- 权限层级:学生 → 教师 → 学校管理员 → 平台管理员
- 每个用户只能有一个直接上级,形成树状权限结构
- 平台管理员没有上级,
parent_user_id为null
6. 路由设计
6.1 用户查询接口
6.1.1 通用用户查询
GET
/users- 权限:
- 老师:默认返回自己任教班级学生,支持
class_id精确过滤;禁止跨校 - 学校管理员:本校范围用户;支持
role、q(用户名/真实名模糊)、分页 - 平台管理员:全平台;同上
- 老师:默认返回自己任教班级学生,支持
- 查询参数:
role?=student|teacher|school_adminschool_id?class_id?q?(搜索关键词)page?=1size?=20
- 响应示例:json
{ "items": [ { "id": 1, "username": "stu_001", "real_name": "张三", "role": "student", "school_id": 1, "avatar_url": null, "created_at": "2025-01-01T00:00:00Z", "parent_user_id": 15 } ], "total": 100, "page": 1, "size": 20 }
- 权限:
GET
/users/{user_id}- 权限:本人/本班(老师)/本校(学校管理员)/全平台(平台管理员)
- 响应:单个用户详细信息(脱敏)
6.1.2 专门的角色列表接口
GET
/users/students- 权限:老师(本班学生)/学校管理员(本校)/平台管理员(全平台)
- 查询参数:
school_id?:学校ID(老师必填,管理员可选)class_id?:班级ID(老师必填,管理员可选)q?:搜索关键词page?=1size?=20
- 说明:专门用于获取学生列表,支持按学校、班级筛选
GET
/users/teachers- 权限:学校管理员(本校)/平台管理员(全平台)
- 查询参数:
school_id?:学校ID(学校管理员必填,平台管理员可选)class_id?:班级ID(可选,查看某班级的任课教师)q?:搜索关键词page?=1size?=20
- 说明:专门用于获取教师列表
GET
/users/school_admins- 权限:平台管理员
- 查询参数:
school_id?:学校ID(可选)q?:搜索关键词page?=1size?=20
- 说明:专门用于获取学校管理员列表
GET
/users/platform_admins- 权限:平台管理员
- 查询参数:
q?:搜索关键词page?=1size?=20
- 说明:专门用于获取平台管理员列表
6.2 用户创建接口(限制自助注册)
6.2.1 创建学生账号
- POST
/schools/{school_id}/users:student- 说明:创建本校学生账号;禁止学生自建
- 权限:学校管理员/平台管理员
- 请求示例:json
{ "username": "stu_001", "password": "Init@123", "real_name": "张三", "class_ids": [101, 102] } - 说明:
parent_user_id由系统自动设置为当前创建者(学校管理员或平台管理员)的ID - 响应:201 + 用户对象(脱敏)
6.2.2 创建教师账号
- POST
/schools/{school_id}/users:teacher- 说明:创建本校教师账号;支持指定任教班级
- 权限:学校管理员/平台管理员
- 请求示例:json
{ "username": "t_zhang", "password": "Init@123", "real_name": "张老师", "class_ids": [101] } - 说明:
parent_user_id由系统自动设置为当前创建者(学校管理员或平台管理员)的ID - 响应:201 + 用户对象(脱敏)
6.2.3 创建学校管理员账号
- POST
/schools/{school_id}/users:school_admin- 说明:创建学校管理员账号
- 权限:仅平台管理员
- 请求示例:json
{ "username": "admin_001", "password": "Admin@123", "real_name": "李主任" } - 说明:
parent_user_id由系统自动设置为当前创建者(平台管理员)的ID - 响应:201 + 用户对象(脱敏)
6.3 用户更新与状态管理
6.3.1 更新用户信息
- PUT
/users/{user_id}- 权限:
- 学生:仅本人且字段限于
real_name,avatar_url - 老师:仅本班学生有限字段(例如
real_name),不含role/school_id/username - 学校管理员:本校用户,可更新基础字段,不含
role=platform_admin - 平台管理员:无限制
- 学生:仅本人且字段限于
- 请求示例:json
{ "real_name": "张三丰", "avatar_url": "/static/avatars/001.jpg" }
- 权限:
6.3.2 重置用户密码
- POST
/users/{user_id}:reset_password- 权限:老师(本班学生)、学校管理员(本校用户)、平台管理员
- 入参:json
{ "new_password": "NewPass@123" } - 或:空参数(系统生成并返回临时密码)
6.3.3 启用/禁用账号
- POST
/users/{user_id}:status- 作用:启用/禁用账号(软删除)
- 权限:学校管理员(本校用户)/平台管理员
- 入参:json
{ "disabled": true, "reason": "违反校规" }
6.3.4 删除账号
- DELETE
/users/{user_id}- 权限:建议仅平台管理员可硬删除;学校管理员默认以停用代替
- 说明:删除前会检查关联数据,如有课程、作业等关联则拒绝删除
6.4 班级成员与教师管理
6.4.1 班级成员管理
GET
/classes/{class_id}/members- 权限:任教老师/学校管理员/平台管理员
- 响应:班级学生列表
POST
/classes/{class_id}/members- 说明:添加学生到班级(批量)
- 权限:任教老师(限本班)/学校管理员(本校)/平台管理员
- 入参:json
{ "user_ids": [1, 2, 3] } - 或:json
{ "username_list": ["stu_1", "stu_2"] }
DELETE
/classes/{class_id}/members/{user_id}- 权限:同上;用于移除班级学生
6.4.2 班级教师管理
GET
/classes/{class_id}/teachers- 权限:任教老师/学校管理员/平台管理员
- 响应:班级教师列表
POST
/classes/{class_id}/teachers- 说明:指派老师到班级
- 权限:学校管理员/平台管理员
- 入参:json
{ "teacher_id": 7, "role": "instructor" }
DELETE
/classes/{class_id}/teachers/{teacher_id}- 权限:学校管理员/平台管理员 或 教师本人退出本班(仅影响映射关系)
6.5 学校管理接口(平台管理员专用)
6.5.1 学校管理
GET
/schools- 权限:学校管理员(仅本校)/平台管理员(全平台)
- 查询参数:
q?:学校名称搜索region?:地区筛选page?=1size?=20
POST
/schools- 说明:创建新学校
- 权限:仅平台管理员
- 请求示例:json
{ "name": "新希望中学", "region": "北京市朝阳区" }
PUT
/schools/{school_id}- 说明:更新学校信息
- 权限:学校管理员(本校)/平台管理员(全平台)
DELETE
/schools/{school_id}- 说明:删除学校(需检查是否有关联用户)
- 权限:仅平台管理员
6.5.2 学校管理员管理
GET
/schools/{school_id}/admins- 说明:获取指定学校的管理员列表
- 权限:平台管理员
- 响应:学校管理员列表
POST
/schools/{school_id}/admins- 说明:为学校指派管理员
- 权限:仅平台管理员
- 请求示例:json
{ "user_id": 123, "role": "school_admin" }
DELETE
/schools/{school_id}/admins/{user_id}- 说明:撤销学校管理员权限
- 权限:仅平台管理员
6.6 学校品牌(Logo)
GET
/branding/me- 说明:返回当前登录用户所属学校的品牌信息
- 权限:登录用户
- 响应示例:json
{ "school_id": 3, "logo_url": "/static/images/schools/3/a1b2c3.png" }
GET
/schools/{school_id}/branding- 说明:读取指定学校品牌信息
- 权限:学校管理员(本校)/平台管理员
- 响应示例:json
{ "school_id": 3, "logo_url": "/static/images/schools/3/a1b2c3.png" }
PUT
/schools/{school_id}/branding- 说明:更新品牌信息(当前仅支持
logo_url);通常用于“先上传图片得到 URL,再回写”场景 - 权限:学校管理员(本校)/平台管理员
- 请求示例:json
{ "logo_url": "/static/images/schools/3/a1b2c3.png" } - 响应:同上
- 说明:更新品牌信息(当前仅支持
POST
/schools/{school_id}/branding/logo- 说明:一体化上传并设置学校 Logo(multipart 上传图片,服务端保存后直接写入
schools.logo_url) - 权限:学校管理员(本校)/平台管理员
- 请求:
multipart/form-data,字段名file,支持.png/.jpg/.jpeg/.webp/.gif/.bmp - 响应示例:json
{ "school_id": 3, "logo_url": "/static/images/schools/3/fe21ac.png" }
- 说明:一体化上传并设置学校 Logo(multipart 上传图片,服务端保存后直接写入
7. 响应与脱敏
7.1 用户对象脱敏
- 用户对象对外统一脱敏:不返回
password_hash - 建议统一返回:
{"id","username","real_name","avatar_url","role","school_id","parent_user_id","created_at"} - 敏感操作(如重置密码)返回临时密码时需特殊处理
parent_user_id字段用于显示用户的上级关系,有助于权限管理
7.2 错误码规范
401:未认证403:权限不足404:资源不存在400:参数错误409:冲突(用户名已存在/关系已存在)422:数据验证失败
8. 安全与审计建议
8.1 密码安全
- 强制密码复杂度与最小长度(建议:8位以上,包含大小写字母、数字、特殊字符)
- 重置密码默认
require_password_reset = true - 密码历史记录(防止重复使用)
8.2 操作审计
- 所有敏感操作(创建/重置密码/禁用/删除)写入
token_log或审计日志表 - 记录操作人、操作时间、操作类型、操作对象、操作结果
8.3 接口安全
- 接口速率限制与防暴力破解:登录/重置密码相关接口需限流与告警
- 敏感操作需要二次确认(如删除账号)
- 跨域访问控制
9. 请求/响应示例
9.1 创建学生账号
bash
# 学校管理员创建学生
curl -X POST http://localhost:8000/schools/3/users:student \
-H 'Authorization: Bearer TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"username": "s001",
"password": "Init@123",
"real_name": "张三",
"class_ids": [101]
}'响应(201):
json
{
"id": 201,
"username": "s001",
"real_name": "张三",
"role": "student",
"school_id": 3,
"avatar_url": null,
"created_at": "2025-01-01T10:00:00Z",
"parent_user_id": 15
}9.2 获取学生列表
bash
# 老师获取本班学生列表
curl -X GET "http://localhost:8000/users/students?class_id=101&page=1&size=20" \
-H 'Authorization: Bearer TOKEN'响应:
json
{
"items": [
{
"id": 201,
"username": "s001",
"real_name": "张三",
"role": "student",
"school_id": 3,
"avatar_url": null,
"created_at": "2025-01-01T10:00:00Z",
"parent_user_id": 15
}
],
"total": 1,
"page": 1,
"size": 20
}9.3 重置学生密码
bash
# 老师重置本班学生密码
curl -X POST http://localhost:8000/users/201:reset_password \
-H 'Authorization: Bearer TOKEN' \
-H 'Content-Type: application/json' \
-d '{"new_password": "New@12345"}'响应:
json
{
"message": "密码重置成功",
"user_id": 201,
"reset_at": "2025-01-01T11:00:00Z"
}9.4 平台管理员创建学校管理员
bash
# 平台管理员创建学校管理员
curl -X POST http://localhost:8000/schools/3/users:school_admin \
-H 'Authorization: Bearer TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"username": "admin_001",
"password": "Admin@123",
"real_name": "李主任"
}'10. 与现有代码的对接点
10.1 鉴权依赖
app/api/deps.py中get_current_user、get_teacher_or_admin- 可新增
require_roles(*roles)辅助函数 - 可新增
require_school_scope(school_id)学校作用域校验
10.2 模型复用
app/models/user.py的UserRole已覆盖四类角色- 结合
School、Class、ClassMember、ClassTeacher完成范围校验 - 元数据:
/meta/schools、/meta/classes可复用现有端点作为选择器
10.3 服务层设计
- 新建
app/services/user_management_service.py - 新建
app/services/school_management_service.py - 实现权限校验、范围控制、批量操作等核心逻辑
11. 后续实现顺序(建议)
11.1 第一阶段:基础用户管理
- 补充用户路由模块
app/api/users.py与schemas - 实现基础的 CRUD 操作(创建、查询、更新、删除)
- 实现权限校验中间件
11.2 第二阶段:角色与范围管理
- 实现学校作用域创建账号与班级成员管理 Service(含越权校验)
- 实现班级成员和教师的增删改查
- 实现用户角色管理
- 实现基于
parent_user_id的权限继承校验 - 实现上级用户管理下级用户的权限控制
11.3 第三阶段:高级功能
- 增加
users.disabled、users.require_password_reset字段的迁移(可选) - 接入审计日志与限流(登录/重置密码)
- 实现学校管理功能(平台管理员专用)
11.4 第四阶段:测试与优化
- 添加测试:角色越权、班级边界、跨校限制、脱敏字段校验
- 测试基于
parent_user_id的权限继承逻辑 - 测试上级用户管理下级用户的权限边界
- 性能优化:索引优化、查询优化
- 文档完善:API 文档、使用示例
12. 注意事项
12.1 数据一致性
- 删除用户前检查关联数据(课程、作业、班级关系等)
- 删除上级用户前检查是否有下级用户依赖(
parent_user_id引用) - 批量操作时使用事务确保数据一致性
- 软删除优先于硬删除
- 维护
parent_user_id的引用完整性,避免悬空引用
12.2 性能考虑
- 大量用户查询时使用分页
- 复杂查询使用数据库索引优化
- 缓存常用数据(如学校列表、班级列表)