220 lines
8.3 KiB
Markdown
220 lines
8.3 KiB
Markdown
# 结果提取与用户权限审计(2026-06-30)
|
||
|
||
## 1. 审计范围
|
||
|
||
本次审计聚焦“结果提取”相关入口和用户权限边界,覆盖:
|
||
|
||
- 前端结果提取工作台:`frontend/src/ResultExtractionPanel.jsx`
|
||
- D-InSAR 结果管理页:`frontend/src/DinsarProductsPanel.jsx`
|
||
- D-InSAR 结果导出接口:`POST /api/dinsar-results/export`
|
||
- D-InSAR 生产结果提取与登记接口:`POST /api/idl/extract-disp`
|
||
- 用户与权限模型:`auth_users.role`、全局认证守卫、用户管理页
|
||
|
||
本次文档只记录审计结论和后续设计约束,不包含代码修复。
|
||
|
||
## 2. 当前实现事实
|
||
|
||
### 2.1 两条“提取”链路
|
||
|
||
当前系统里“结果提取”实际包含两种不同语义:
|
||
|
||
1. **生产结果入库**
|
||
- 前端入口:`DinsarProductsPanel.jsx`
|
||
- 后端入口:`POST /api/idl/extract-disp`
|
||
- 后台任务:`EXTRACT_DINSAR_PRODUCTS`
|
||
- 作用:从生产目录提取 D-InSAR 位移结果,发布成标准结果包,并重建结果 catalog。
|
||
|
||
2. **成果交付导出**
|
||
- 前端入口:`ResultExtractionPanel.jsx`
|
||
- 后端入口:`POST /api/dinsar-results/export`
|
||
- 作用:从已经登记的 D-InSAR catalog 中选择成果,复制到服务器指定交付目录。
|
||
|
||
这两条链路目前在产品文案上都叫“提取”,容易让用户混淆“入库”和“交付”。
|
||
|
||
### 2.2 当前接入状态
|
||
|
||
`ResultExtractionPanel.jsx` 中的通道状态:
|
||
|
||
| 通道 | 当前状态 | 说明 |
|
||
| --- | --- | --- |
|
||
| D-InSAR 结果 | 已接入 | 支持查询已登记结果并导出到服务器目录 |
|
||
| SBAS-InSAR 结果 | 半接入 | 可读取目录样例,但统一提取接口未实现 |
|
||
| LT-1 正射结果 | 占位 | 单景/正射结果 catalog 与导出链路未完成 |
|
||
| Sentinel-1 正射结果 | 占位 | 生产和导出链路未完成 |
|
||
| GF3 SARscape `_geo` | 占位 | 登记/标准化思路存在,统一导出接口未完成 |
|
||
|
||
## 3. 当前权限模型
|
||
|
||
系统当前只有两类角色:
|
||
|
||
- `admin`
|
||
- `viewer`
|
||
|
||
定义位置:`backend/app/auth_service.py`
|
||
|
||
全局认证守卫位于 `backend/app/routers/dependencies.py`:
|
||
|
||
- `GET / HEAD / OPTIONS` 默认视为只读操作,登录用户可访问。
|
||
- 除少数显式安全 POST 外,非只读请求要求 `admin`。
|
||
- 非管理员执行写操作会被拒绝,返回 `403 Read-only account cannot perform this operation.`
|
||
|
||
前端在 `App.jsx` 中把非管理员账号映射为 `readOnly`:
|
||
|
||
- viewer 可以浏览结果、查看任务、查看 catalog。
|
||
- viewer 不能提交生产、扫描、提取、导出、删除、修改。
|
||
- admin 拥有所有写权限,包括生产、扫描、结果入库、结果导出、用户管理和运维配置。
|
||
|
||
后端没有依赖前端按钮禁用来保护写操作。`/api/idl/extract-disp` 和 `/api/dinsar-results/export` 都显式要求 `admin`,这一点是正确的。
|
||
|
||
## 4. 审计发现
|
||
|
||
### P1:成果交付权限与系统管理员权限耦合过重
|
||
|
||
当前只有 `admin` 能执行成果导出,但 `admin` 同时拥有用户管理、系统配置、生产扫描、删除记录等高权限。
|
||
|
||
从业务职责看,成果交付导出不应天然等同于系统管理员权限。后续应拆出更细的权限,例如:
|
||
|
||
- `operator`:可提交生产任务、结果入库、目录重建。
|
||
- `exporter`:可导出已登记成果到受控交付目录。
|
||
- `viewer`:只读浏览、预览、查询。
|
||
- `admin`:用户管理、系统配置、根目录维护、许可证和高风险运维。
|
||
|
||
### P1:结果导出是同步请求,存在 504 风险
|
||
|
||
`POST /api/dinsar-results/export` 在请求线程内执行文件复制,最多允许 500 个结果 ID。成果文件较大或目标目录较慢时,容易再次触发前端或 Nginx 超时。
|
||
|
||
后续应改成后台任务:
|
||
|
||
- 接口只创建任务并返回 `task_id`。
|
||
- 文件复制由 worker 执行。
|
||
- 前端通过任务中心/结果提取工作台展示进度、成功数、失败数和目标目录。
|
||
|
||
### P1:生产结果入库缺少显式操作审计
|
||
|
||
`/api/dinsar-results/export` 已写入 `dinsar_results_exported` 审计日志。
|
||
|
||
`/api/idl/extract-disp` 当前会创建系统任务,但缺少独立的操作审计记录。它会改变结果 catalog,应记录:
|
||
|
||
- 操作用户
|
||
- 源生产目录
|
||
- 目标发布目录
|
||
- 创建的 `task_id` / `job_id`
|
||
- 完成后的 processed/copied/failed/published/registered 数量
|
||
|
||
### P2:页面命名和工作流边界不清
|
||
|
||
当前“D-InSAR 结果提取与登记”和“结果提取工作台”容易混淆。
|
||
|
||
建议命名:
|
||
|
||
- “生产结果入库”:从生产目录提取并登记为系统 catalog。
|
||
- “成果交付导出”:从已登记 catalog 选择成果并复制到交付目录。
|
||
|
||
这两个动作应该放在同一结果管理域下,但用不同分区和不同权限提示。
|
||
|
||
### P2:占位通道需要降低可执行暗示
|
||
|
||
SBAS、LT-1 正射、Sentinel-1 正射、GF3 `_geo` 目前不应被呈现成可执行导出能力。
|
||
|
||
建议 UI 明确显示:
|
||
|
||
- `已接入`
|
||
- `目录可查,导出未接入`
|
||
- `规划中`
|
||
- `不可执行`
|
||
|
||
并隐藏或禁用导出按钮,避免用户误以为功能已经上线。
|
||
|
||
### P2:导出目录策略需要产品化
|
||
|
||
当前后端已有 `_validate_export_path()` 和 `ALLOWED_EXPORT_DIRS` 约束能力,但前端仍允许用户输入服务器绝对路径。
|
||
|
||
后续建议:
|
||
|
||
- 普通业务用户不输入任意服务器路径。
|
||
- 管理员在系统配置中维护“交付目录白名单”。
|
||
- 结果导出页只让用户选择白名单目录和子任务名。
|
||
- 审计记录保存最终解析后的服务器路径。
|
||
|
||
### P3:部分前端文案存在历史编码损坏
|
||
|
||
`DinsarProductsPanel.jsx`、`ResultExtractionPanel.jsx`、`UserAdminPanel.jsx` 等文件存在局部中文乱码。功能不一定受影响,但会降低维护性和产品可信度。
|
||
|
||
建议后续单独做一次 UTF-8 文案修复,不与权限重构混在同一次提交中。
|
||
|
||
## 5. 建议目标模型
|
||
|
||
### 5.1 功能分区
|
||
|
||
结果管理应拆成三个清晰分区:
|
||
|
||
1. **产品目录**
|
||
- 查看已登记成果。
|
||
- 预览、筛选、查看详情。
|
||
- viewer 可访问。
|
||
|
||
2. **生产结果入库**
|
||
- 从生产结果根目录扫描、提取、发布、登记。
|
||
- operator/admin 可执行。
|
||
|
||
3. **成果交付导出**
|
||
- 从 catalog 选择成果,导出到受控交付目录。
|
||
- exporter/operator/admin 可执行。
|
||
|
||
### 5.2 权限矩阵建议
|
||
|
||
| 操作 | viewer | exporter | operator | admin |
|
||
| --- | --- | --- | --- | --- |
|
||
| 查看结果 catalog | yes | yes | yes | yes |
|
||
| 查看预览与详情 | yes | yes | yes | yes |
|
||
| 生产结果入库 | no | no | yes | yes |
|
||
| 目录重建/发布 | no | no | yes | yes |
|
||
| 成果交付导出 | no | yes | yes | yes |
|
||
| 生产任务提交 | no | no | yes | yes |
|
||
| 用户管理 | no | no | no | yes |
|
||
| 根目录/许可证/运维配置 | no | no | no | yes |
|
||
|
||
实现上可以先保留 `role` 字段,扩展角色枚举;长期可引入权限位表,避免角色继续膨胀。
|
||
|
||
## 6. 推荐实施顺序
|
||
|
||
### 阶段 1:修正产品语义和审计
|
||
|
||
- 页面文案区分“生产结果入库”和“成果交付导出”。
|
||
- `/api/idl/extract-disp` 增加操作审计。
|
||
- 结果提取工作台明确标注未接入通道。
|
||
- 修复相关页面乱码文案。
|
||
|
||
### 阶段 2:导出任务化
|
||
|
||
- 新增 `EXPORT_DINSAR_RESULTS` 后台任务类型。
|
||
- `/api/dinsar-results/export` 改为返回 `task_id`。
|
||
- 前端展示导出任务进度和失败明细。
|
||
- 导出结果保留 task log 和 audit log。
|
||
|
||
### 阶段 3:权限细分
|
||
|
||
- 扩展角色:`viewer/exporter/operator/admin`。
|
||
- 用户管理页支持新角色说明。
|
||
- 后端增加能力级依赖,例如 `require_capability("result.export")`。
|
||
- 所有高风险写操作按 capability 而不是只按 admin 判断。
|
||
|
||
### 阶段 4:交付目录白名单产品化
|
||
|
||
- 将 `ALLOWED_EXPORT_DIRS` 从环境变量能力升级为系统配置/受控根目录。
|
||
- 前端从白名单选择交付根目录。
|
||
- 用户只输入子目录名或交付批次名。
|
||
|
||
## 7. 验收标准
|
||
|
||
完成上述改造后,应满足:
|
||
|
||
1. viewer 能看结果,不能导出、不能入库。
|
||
2. exporter 能导出已登记成果,但不能提交生产、不能用户管理。
|
||
3. operator 能生产、入库、导出,但不能用户管理和系统配置。
|
||
4. admin 保留全部权限。
|
||
5. 所有入库和导出动作都有 task log 和 audit log。
|
||
6. 大批量导出不再产生 HTTP 504。
|
||
7. 未实现通道在 UI 上不会被误认为可执行功能。
|
||
|