Files
xh-medical-sign-web/clinical-web/docs/users-permissions-api.md
T

14 KiB
Raw Blame History

用户与权限页面接口核验与后端缺口

核验基准:MEDISIGN 患者电子签 API 文档(https://ipad.shenynet.com/doc.html#/home)。

1. 核验结论

当前页面已经可以使用后端接口完成用户列表和用户生命周期的主要操作:查询、分页、关键字搜索、院区筛选、查看详情、新增、编辑和停用。角色列表也已经接入,用于展示角色卡片。

最新接口文档没有提供用户与角色的关联数据,因此用户表中的角色只能显示“未返回角色”;角色接口也没有返回用户人数,角色卡片不会再根据当前用户列表臆造人数。

页面上暂时保留但无法真正执行的功能是:

  • 批量导入用户;
  • 重置密码;
  • 为用户分配或移除角色;
  • 角色人数统计。

另外,/api/v1/permissions 管理的是 API 权限定义(资源、路径和动作),不是用户或角色的权限分配关系。模板文档权限使用 /api/v1/templates/{templateId}/permissions,两者也不能混用。

2. 当前已接入接口

页面功能 接口 状态 说明
用户列表 GET /api/v1/users 已接入 支持 page、size、keyword、campusId;前端已接分页
用户详情 GET /api/v1/users/{id} 已接入 用于打开编辑弹窗
新增用户 POST /api/v1/users 已接入 创建时提交账号、密码、基础资料、院区、科室和数据范围
编辑用户 PUT /api/v1/users/{id} 已接入 不修改用户名和密码
停用用户 DELETE /api/v1/users/{id} 已接入 后端是软停用,前端有二次确认
角色列表 GET /api/v1/roles 已接入 支持 page、size、keyword;最新响应没有 userCount
院区字典 GET /api/v1/campuses 已接入 用于院区显示和用户表单
科室字典 GET /api/v1/departments 已接入 用于科室显示和用户表单,可按院区筛选

2.1 已遵守的接口约束

  • 所有请求使用统一响应包装,并通过 X-Token 携带登录令牌;
  • 用户列表的 page 从 1 开始,size 范围为 1–200;
  • 创建用户时密码只出现在请求中,不能出现在任何响应或日志中;
  • 编辑接口不接收用户名和密码;
  • 停用接口不执行物理删除,只将状态改为 DISABLED;
  • 用户接口返回的手机号和邮箱可能是脱敏值。前端编辑时,如果用户没有重新填写,不会把脱敏值回传覆盖原联系方式;
  • 用户角色、角色人数和最终权限判断必须由后端提供和校验,前端不自行推导。

3. 建议补充的后端接口

3.1 用户角色关联(最高优先级)

用户列表和详情最好直接在 UserResponse 中增加角色摘要,避免列表为每个用户额外请求一次接口:

{
  "roles": [
    {
      "id": "角色 UUID",
      "code": "DOCTOR",
      "name": "医生"
    }
  ]
}

同时提供角色关系的读取和覆盖更新接口,供用户编辑弹窗使用:

GET /api/v1/users/{userId}/roles
PUT /api/v1/users/{userId}/roles
Content-Type: application/json

请求体建议为:

{
  "roleIds": ["角色 UUID 1", "角色 UUID 2"]
}

PUT 使用“完整替换”语义,便于前端重复提交保持幂等。响应建议返回用户和最新角色摘要:

{
  "code": 0,
  "message": "OK",
  "data": {
    "userId": "用户 UUID",
    "roles": [
      {
        "id": "角色 UUID",
        "code": "DOCTOR",
        "name": "医生"
      }
    ],
    "updatedAt": "2026-09-01T08:00:00Z"
  }
}

后端应校验角色是否存在、是否停用、当前操作人是否有分配权限,并记录角色变更审计日志。建议错误码包括 400、401、403、404 和 409。

3.2 重置密码

建议提供:

POST /api/v1/users/{userId}/password/reset
Content-Type: application/json

请求体:

{
  "newPassword": "管理员输入的新密码",
  "forceChangeOnNextLogin": true
}

响应使用 ApiResponseVoid,不返回密码:

{
  "code": 0,
  "message": "密码已重置",
  "data": {}
}

密码必须在服务端进行强度校验和哈希存储;密码不能写入日志、审计详情或响应。若产品要求服务端生成临时密码,应通过受控的一次性展示或院内安全渠道交付,不建议作为普通接口字段长期返回。建议错误码包括 400、401、403、404 和 429。

3.3 批量导入用户

批量导入不建议直接把文件上传后立即写库,建议拆成“预览校验 + 确认导入”:

POST /api/v1/users/import/preview
Content-Type: multipart/form-data

表单字段:

字段 类型 说明
file file CSV 或 XLSX 文件,建议限制文件大小和行数
campusId UUID 没有院区列时使用的默认院区,可选

预览响应至少应包含:

{
  "code": 0,
  "data": {
    "importId": "导入批次 UUID",
    "fileName": "users.xlsx",
    "totalRows": 100,
    "validRows": 96,
    "invalidRows": 4,
    "rows": [
      {
        "rowNo": 12,
        "status": "INVALID",
        "errors": ["用户名已存在"],
        "username": "zhangsan",
        "displayName": "张三"
      }
    ]
  }
}

确认导入:

POST /api/v1/users/import/commit
Content-Type: application/json
{
  "importId": "导入批次 UUID"
}

如果导入量较大,确认接口返回任务号并异步执行:

GET /api/v1/users/import/jobs/{jobId}

导入文件建议支持 username、displayName、employeeNo、phone、email、campusId、departmentId、roleCodes 和 dataScope 列。密码应遵循统一的临时密码或首次登录设置策略,不建议在普通导入文件中保存明文密码。导入必须逐行返回校验错误,不能因为一行错误而静默跳过整批数据。

3.4 角色人数统计

当前 GET /api/v1/roles 的响应没有 userCount。如果原型需要保留角色卡片人数,建议新增专用汇总接口:

GET /api/v1/roles/summary?campusId={campusId}

响应建议为:

{
  "code": 0,
  "data": [
    {
      "roleId": "角色 UUID",
      "code": "DOCTOR",
      "name": "医生",
      "description": "可查看并发起签署任务",
      "status": "ENABLED",
      "userCount": 18
    }
  ]
}

需要和后端确认人数口径:建议只统计当前操作人数据权限范围内、状态为 ENABLED 的用户,并按当前页面选择的院区过滤;如果产品要统计全院,应明确忽略页面院区筛选。统计接口也必须执行当前用户的权限范围校验。

3.5 API 权限分配(仅在产品需要时补充)

现有 /api/v1/permissions 只是 API 权限目录的增删改查。若需要让管理员把 API 权限分配给角色,还需要关系接口:

GET /api/v1/roles/{roleId}/permissions
PUT /api/v1/roles/{roleId}/permissions

请求体可以使用完整替换语义:

{
  "permissionIds": ["API 权限 UUID 1", "API 权限 UUID 2"]
}

这组接口与模板文档权限接口不同。模板的角色、科室和用户授权继续使用:

GET /api/v1/templates/{templateId}/permissions
POST /api/v1/templates/{templateId}/permissions
DELETE /api/v1/templates/{templateId}/permissions/{permissionId}

4. 接口错误与审计要求

所有新增接口建议继续使用统一响应格式,并至少覆盖:

HTTP 状态 场景
400 参数、格式、文件内容或业务校验失败
401 未登录或令牌失效
403 当前用户没有对应管理权限
404 用户、角色、导入批次或权限不存在
409 用户名重复、角色关系并发冲突等
429 密码重置或批量任务触发频率限制
500 服务端异常

用户创建、编辑、停用、密码重置、角色变更和批量导入都应产生审计记录,至少包含操作人、目标用户、操作类型、结果、时间和链路追踪 ID;不得记录密码、完整手机号、身份证号或完整病历信息。

5. 推荐实施顺序

  1. 先补用户角色摘要和角色绑定接口,解除用户表“未返回角色”的限制;
  2. 补密码重置接口,前端再把现有提示改为重置密码弹窗;
  3. 补批量导入预览、确认和任务查询;
  4. 根据产品是否保留角色卡片人数,补角色统计接口;
  5. 如果要管理 API 权限,再补角色与 API 权限的关联接口,不能复用 /api/v1/permissions CRUD 代替。

6. 以最新 OpenAPI 核验授权链路(2026-09-02)

6.1 已有能力与当前状态

核验项 最新接口/实现 状态
登录认证 POST /api/v1/auth/login 返回 X-Token、dataScope 和 permissions 已具备
当前用户刷新 GET /api/v1/auth/me 返回 UserResponse,该 schema 没有 permissions 字段不足
用户页面登录保护 路由只判断是否存在 Token 已具备认证,缺少权限门控
用户/角色/权限 API /users、/roles、/permissions 的 CRUD 接口均在 OpenAPI 中 API 封装已接入;权限目录暂无对应页面
用户角色关联 最新 OpenAPI 没有用户-角色关系接口 后端缺口
角色 API 权限关联 最新 OpenAPI 没有角色-API 权限关系接口 后端缺口
模板文档权限 /api/v1/templates/{templateId}/permissions 独立能力,不能替代 API 权限

当前侧边栏会向所有已登录用户展示“用户与权限”和“文档权限”,直接输入管理端 URL 也可以进入;按钮是否真正可执行目前依赖后端返回 403。这不能替代前端菜单/路由门控,但安全边界必须仍由后端执行。

6.2 后端需要确认或补充的内容

  1. 补齐当前用户权限刷新

    建议修改 GET /api/v1/auth/me 的成功响应,使其至少包含登录摘要中的 dataScope 和 permissions: string[]。权限集合只返回当前用户实际拥有的启用权限,不返回密码或未脱敏敏感信息。若不改现有接口,需新增等价的 GET /api/v1/auth/me/permissions,但应只保留一个权威来源。

  2. 定义并初始化权限编码

    OpenAPI 只建议使用 system:<资源>:<动作> 格式,没有给出本页面实际权限编码。建议后端确认并初始化:

    • system:user:query、system:user:create、system:user:update、system:user:disable;
    • system:role:query、system:role:create、system:role:update、system:role:disable;
    • system:permission:query、system:permission:create、system:permission:update、system:permission:disable。

    上述编码是建议值,最终以后端权限中心的命名为准;报表权限还应单独定义 query/export 权限,不能用页面名称或前端隐藏按钮代替。

  3. 提供 API 权限关系接口

    /api/v1/permissions 只负责权限目录增删改查。若管理端需要真正分配 API 权限,需提供:

    GET /api/v1/roles/{roleId}/permissions
    PUT /api/v1/roles/{roleId}/permissions
    Content-Type: application/json
    
    { "permissionIds": ["API 权限 UUID 1", "API 权限 UUID 2"] }
    

    用户角色关系仍需提供:

    GET /api/v1/users/{userId}/roles
    PUT /api/v1/users/{userId}/roles
    

    关系更新建议使用完整替换、幂等语义,校验角色/权限状态和当前操作人权限,并记录审计日志。

  4. 所有管理接口必须服务端授权

    用户、角色、API 权限及模板权限接口都应按操作区分 query/create/update/disable 权限;用户 dataScope 只能限制数据范围,不能替代操作权限。客户端传入的 campusId、departmentId 不得扩大操作人的数据范围,越权统一返回 403。

  5. 补齐错误和审计契约

    所有授权关系和管理写接口建议明确 400/401/403/404/409/500;权限变更、用户停用、角色绑定和 API 权限绑定应记录操作人、目标、动作、结果、时间和 traceId,不记录密码、完整手机号、身份证号或病历内容。

6.3 前端联调验收

  • 登录后调用 /auth/me 能拿到最新权限,权限撤销后旧会话访问受保护接口立即得到 403;
  • 无用户查询权限的账号不能看到用户数据,直接访问 URL 也不能绕过后端;
  • 只有对应 create/update/disable 权限的按钮才可用,前端隐藏只是体验优化,不能作为安全措施;
  • 用户角色和角色 API 权限变更后,重新登录或刷新当前用户即可看到最新权限;
  • Mock 模式仅用于页面演示,真实权限验证必须设置 VITE_USE_MOCK=false,使用不同权限账号检查 Network 请求和 401/403 响应。