# 用户分组接口与权限说明 适用项目:Scert。更新日期:2026-09-27。 ## 页面入口 - 系统设置位于侧栏的系统管理区域,打开已有设置面板。 - 修改密码位于用户管理页面,修改当前登录账号的密码。 - 默认分组置顶并始终展开;命名分组初始折叠。 - 普通用户进入用户中心,只显示本人资料及修改密码,不显示分组。 ## 可见范围 | 角色 | 用户读取范围 | 分组关系 | 用户新增、编辑、删除 | |---|---|---|---| | 超级管理员 | 全部用户和分组 | 主账号保持受保护 | 允许,主账号保护规则不变 | | 管理员 | 自己及所属组成员的并集 | 可加入多个命名分组 | 不允许 | | 普通用户 | 仅自己 | 最多一个命名分组 | 不允许 | 没有命名分组的账号属于默认分组。未分组管理员可见默认组成员,但不可见其他超级管理员。管理员读取多组成员时,只返回双方共同的分组,不泄露对方的其他组名。这里限定的是用户列表可见范围,不代表域名、证书、服务器资源已经实现分组隔离。 ## 接口 沿用现有会话认证与同源校验。 | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/v1/users` | 按角色过滤的用户列表 | | GET | `/api/v1/users/:id` | 查询可见用户;越权与不存在均返回 404 | | POST | `/api/v1/users` | 超级管理员创建用户 | | PUT | `/api/v1/users/:id` | 超级管理员更新用户 | | DELETE | `/api/v1/users/:id` | 超级管理员删除用户 | 列表响应增加 `current_role`、`current_user_id`。用户对象的 `groups` 为字符串数组;默认组和普通用户读取时省略该字段。密码摘要不返回。 新增和更新请求支持 `groups`:省略或传 `null` 时,新增使用默认组,更新保留原关系;传 `[]` 清空命名分组、回到默认组。组名去首尾空白、去重并排序,区分大小写,长度为 1 到 32 个字符,不允许控制字符或保留名称“默认分组”。最多 32 个组,普通用户最多 1 个组。多组管理员降级为普通用户时,必须明确保留不超过一个组,否则返回 400,不会静默丢失分组。 分组名称由保存用户时创建;没有独立空组、组重命名或组删除接口。删除最后一个组内成员后,该组不再显示。 ## 数据升级与验证边界 迁移版本 8 为用户表增加可空的 `groups_json` 文本字段。旧记录的空值解释为默认分组,保留原账号、角色和密码摘要。每次读取用户列表时重新读取当前账号分组,不依赖会话中缓存的分组。通过用户管理页面保存变更时,后端会撤销该用户的现有登录会话,包括仅调整分组的情况;该用户下一次请求会返回登录页面,重新登录后应用新的可见范围。不能将仓储层直接更新的单元测试解释为页面调组后无需重新登录。 SQLite 的旧版本升级与重复迁移由专项测试覆盖;MySQL 和 PostgreSQL 提供迁移文件,但本次专项测试不代表这两种数据库已完成真实环境升级验收。 ## 2026年9月27日浏览器实机验收 运行版本为源码提交 `9ac222d6db61ce0daeecb846da42852778a1036c`。本轮延续已部署的 SQLite 现场,没有清库或重新初始化,也没有改变证书、DNS、部署服务器或代理配置。所有用户新增、编辑、登录、改密及删除操作均通过浏览器键鼠完成,没有直接调用实机业务接口或新增辅助测试脚本。 ### 验收数据与结果 临时建立四个账号:管理员甲属于甲、乙两个组;普通成员属于甲组;管理员乙属于乙、丙两个组;另一普通成员不指定分组。所有测试账号保持用户指定的统一测试密码,文档不保存密码。 | 场景 | 本轮实机结果 | |---|---| | 超级管理员查看 | 默认分组置顶且展开,甲、乙、丙组默认折叠,能看到全部组及成员 | | 管理员多组 | 管理员甲可同时加入甲、乙两组,展开后看到本人及双方共同组的成员 | | 隐藏非共同组 | 管理员甲看不到管理员乙所属的丙组,也看不到默认组成员或主超级管理员 | | 普通用户多组限制 | 添加第二组时明确提示先移除原分组,已有分组保持不变 | | 多组管理员降级 | 选择普通用户后要求先移除多余分组,保存被拦截,未静默丢失原分组 | | 回到默认分组 | 清除管理员甲的命名分组后,其旧会话失效;重新登录只看到本人及默认组普通成员,不显示其他命名组及主超级管理员 | | 普通用户界面 | 只显示本人资料及修改密码,不显示分组、其他用户和管理员控制台 | | 禁用账号 | 禁用管理员甲后,已有会话请求返回登录页;使用原正确密码重新登录也被拒绝 | | 修改密码入口 | 普通用户可从用户管理打开改密弹窗;错误当前密码被拒绝,正确当前密码提交后撤销会话,重新登录成功 | | 删除账号 | 删除已登录普通成员后,该会话下一次刷新返回登录页 | 管理员页面没有用户新增、编辑、禁用或删除控件;直接伪造越权请求的拒绝行为由本地专项测试覆盖,本轮没有通过实机接口绕过键鼠限制。改密使用与当前相同的测试密码以遵循用户的统一密码要求,不据此宣称验证了不同新旧密码的轮换流程。 ### 清理与回归 - [✓] 四个临时账号均经超级管理员页面删除,命名分组随最后成员删除而消失;页面仅保留原受保护主账号。 - [✓] 通过 SQLite 只读统计补充核验:四个测试账号剩余零条、用户总数一条、命名分组关系零条;没有直接修改数据库。 - [✓] 关闭临时角色验收标签页,保留原管理页面及原始测试资源。 - [✓] Scert、Nginx 保持运行,Scert 主进程及重启计数未变,管理入口 HTTP 200、TLS 校验结果为零。 - [✓] 本地重新执行用户分组、会话失效和仓储分组专项测试通过。 本节只证明上述 SQLite 版本的用户界面与对应会话行为,不替代全新生产初始化、正式管理证书签发、邮件找回密码、其他数据库迁移或完整生产部署验收。