Files
kefu/deploy/patient-session-20260918/backend-report.md
T
2026-09-21 10:34:06 +08:00

57 lines
6.1 KiB
Markdown
Raw 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.
# 患者查询会话恢复:后端修复与验证
日期:2026-09-18。修改目录仅 `C:/kefu/wechat_rpa`;未修改 `C:/wechat_rpa`、未部署、未查询真实患者。测试使用合成身份、临时数据库和模拟上游响应,测试运行器阻断外部网络。
## 根因与接口行为
桌面归档凭据与 ZYT 患者查询凭据各有有效期。`admin_backend.Database.desktop_session` 只验证和续期桌面凭据;原保存的 ZYT token 不会跟随桌面心跳续期,因此归档正常不能证明患者查询仍登录。父任务已实测 desktop/me 为 200、ZYT/session 为失效响应,患者查询上游登录超时;本分支未重复访问真实患者。
现在上游 HTTP 401、code=-1 或明确的登录过期消息会映射为:
```json
{"detail":{"code":"zyt_session_expired","message":"ZYT 患者查询登录已过期,请重新验证账号。"}}
```
HTTP 状态为 409。存储的 ZYT 会话缺失或不能解密也采用这一可恢复结果。HTTP 403 或权限拒绝保持可读 403,不触发反复登录。其他患者接口上游故障仍为 502。
新增 `POST /api/v2/desktop/auth/zyt-session`,使用现有桌面 Bearer 凭据,JSON 请求体为 `{"zyt_token":"新的 ZYT token"}`,成功返回 `{"ok":true}`。仅验证为 terminal=7、active 且 `user_id` 与当前桌面账号严格一致的身份可更新。异账号返回 403。接口只更新原租户的加密 ZYT token 与当前账号权限、角色和 root 标识,不创建桌面凭据、不切换账号或租户。
上游身份服务网络错误、超时、HTTP 5xx、无效 JSON/身份数据返回 502,详情 code 为 `zyt_unavailable`,提示稍后重试;真正认证失效为 409,权限拒绝为 403。此分类复用 `zyt_auth` 保存的异常原因;没有修改该适配器或增加部署依赖。
## 并发与权限
`archive_store.refresh_zyt_session` 在 `BEGIN IMMEDIATE` 事务内重新检查原桌面 token、session/device 撤销状态、账号启用状态、账号与设备归属、租户及身份匹配,然后一并更新权限和加密 token。上游验证期间撤销桌面会话、撤销设备或停用账号时,返回 401,不能续活。任何写入失败会回滚权限和 token,避免部分更新。
新事务采用 `expires_at >= now`;现有 `Database.desktop_session` 采用相同条件。没有修改表结构或桌面凭据续期政策。
## 验证结果
- 首轮 60 项全通过:`test_zyt_session_recovery` 当时 18 项,以及 `test_zyt_patient_client`、`test_archive_api`、`test_admin_api.AuthTest` 既有 42 项。结果见 `backend-after.json` / `.log`。
- 补充网络分类后,恢复专项 23 项全部通过,0 失败、0 错误、0 跳过;结果见 `backend-final.json` / `.log`。总计覆盖 65 项不同测试,最后一轮仅重复变更相关专项。
- 新增覆盖:HTTP 401/403、业务过期和权限消息、缺失会话恢复、同账号更新、异账号拒绝、桌面归档仍有效、验证中撤销、设备撤销、账号停用、权限撤回和恢复、事务回滚,以及通过真实 `zyt_auth` 适配器模拟网络异常、超时、HTTP 500/502/503、坏 JSON、非对象响应、缺失身份、HTTP 401、业务过期、HTTP 403。
- 没有用真实患者查询验证恢复后的结果,没有声称生产已部署。生产验证由父任务负责。
## 部署文件
仅四个生产文件:
1. `zyt_patient_client.py`:异常分型及上游错误分类。
2. `archive_api.py`:409/403 对外映射。
3. `archive_store.py`:缺失会话可恢复、原子刷新及再次校验。
4. `admin_api.py`:新请求体和恢复接口、身份服务故障分类。
测试文件 `test_zyt_session_recovery.py` 不必进入运行镜像。原件备份在 `before-backend/`,前后 SHA-256 在 `backend-manifest.json`。没有 `admin_backend.py`、`rbac.py`、`zyt_auth.py` 或 schema 变更。目标目录的 `admin_api.py` 有其他协议版差异,应依据备份与修改后文件定向应用本轮差异。
## PHP 只读审计及边界
本地完整 PHP 源码位于 `C:/zyt`,由现有部署文档定位;本轮只读,未更改。它不能直接证明线上 PHP 版本完全一致。
- `server/config/project.php:36`:管理员 token 有效期 8 小时,临近过期窗口 1 小时;terminal=7 共用此政策。
- `LoginMiddleware.php:53`:过期/失效 token 在普通接口返回“登录超时,请重新登录”。第 63 行在 token 仍有效且进入窗口时调用 `AdminTokenService::overtimeToken`,续原 token,不签发另一枚 token。
- `DesktopController.php:23`:只有专用 `session` 标记免普通登录中间件限制,但方法内部仍验证身份、terminal=7 和账号状态。GET `/adminapi/desktop/session` 经过登录中间件,能保活尚未过期的 token,不能复活已过期 token。该请求首次触发续期时响应里的 expire_time 来自旧的 request.adminInfo,下一次读取才反映新有效期。
- `AdminTokenService.php` 位于 `server/app/adminapi/service/`:登录按 `(admin_id, terminal)` 找会话;过期或禁用同终端多点登录时替换 token,其他情况下复用有效 token 并续期。网页与 terminal=7 分开,不能笼统认为网页登录会踢桌面。
- 没有发现独立 refresh_token 接口;现有可用路径是仍有效时读专用 session 保活,以及过期后走已支持的登录接口重新认证。
- **IP 校验没有 terminal=7 豁免。** `AuthMiddleware.php:50` 对非免登录路由无条件比较缓存 login_ip 与当前请求 IP。专用 `desktop/session` 绕过该限制,`tcm.diagnosis/lists` 不绕过。因此新 token 可被管理服务器验证身份,不等同于必然可以从不同出口查询患者。桌面与管理服务器若共用公网出口则不一定触发;确实不同出口时可能出现“ip地址发生变化,请重新登录”。本轮没有放宽这一限制,也没有改变患者数据范围和菜单权限。
对仍有效 token,可由桌面通过专用 session 做有限保活;过期后仅恢复原账号的患者凭据。若实际部署确认不同出口被拦截,需要另行设计有明确身份和患者数据权限的受限接口,不应全局取消 IP 校验。