feat: add content asset security scanning

This commit is contained in:
Codex
2026-06-29 19:42:05 +08:00
parent d696fc38b0
commit ecd269b548
21 changed files with 936 additions and 75 deletions

View File

@@ -902,14 +902,16 @@ GET /api/catalog/assets/download?assetId=<assetId>
- `download.url` 是短期 attachment URL只给下载动作使用。
- `ASSET_SVIP_REQUIRED`:提示开通对应地区/科目权益。
- `ASSET_UPLOAD_NOT_VERIFIED`:展示“资料正在处理中”,并上报前端日志。
- `ASSET_SECURITY_SCAN_REQUIRED`:展示“资料安全扫描中,请稍后再试”,并重新拉取资源列表或提示后台处理。
- `ASSET_SECURITY_SCAN_FAILED`:展示“资料安全校验未通过,已下架”,学生端不要继续重试旧签名。
- `ASSET_NOT_FOUND` 或列表中资源从 `active` 消失:展示“资源异常已下架”或刷新列表,不要继续使用旧签名 URL。
- `ASSET_PREVIEW_NOT_SUPPORTED`:隐藏预览按钮,仅保留下载或提示不支持预览。
- `previewUrl` 字段只作为公开/托管预览提示,不代表可以绕过接口直接访问。
租户后台上传资料必须走步:
租户后台上传资料必须走步:
```text
sign-upload -> 直传对象存储 -> PUT assets 登记草稿 -> confirm-upload -> sign-preview 验收
sign-upload -> 直传对象存储 -> PUT assets 登记草稿 -> confirm-upload -> 等待 assets worker 安全扫描 -> PUT assets 发布 -> sign-preview 验收
```
后台上传确认:
@@ -924,9 +926,29 @@ sign-upload -> 直传对象存储 -> PUT assets 登记草稿 -> confirm-upload -
}
```
托管对象在确认前会保持 `status=draft``uploadStatus=pending`,学生端不会看到。确认失败时后端返回 `UPLOAD_VERIFICATION_FAILED`,后台必须展示失败原因并允许重新上传,不能前端强行改为已发布。
托管对象在确认前会保持 `status=draft``uploadStatus=pending``securityScanStatus=pending`,学生端不会看到。确认成功后仍保持 `status=draft`,并进入 `uploadStatus=verified``securityScanStatus=pending`;即使传 `publish=true`,后端也不会直接发布。确认失败时后端返回 `UPLOAD_VERIFICATION_FAILED`,后台必须展示失败原因并允许重新上传,不能前端强行改为已发布。
生产环境会定时运行 assets worker 复检对象存储元数据。复检发现对象丢失、跨租户 objectKey、大小/MIME/checksum 不一致时,后端会把资源置为 `uploadStatus=failed` 并从 `active` 退回 `draft`,同时写入 `securityFlags.assetRecheckFailed=true`。租户后台资源列表应对 failed 资源展示异常原因和重新上传入口;学生端不要缓存资料列表和签名 URL 作为长期状态
后台资源列表建议展示这些状态
| 状态 | 前端展示 | 可执行动作 |
| --- | --- | --- |
| `draft/pending/pending` | 待上传确认 | 重新上传、确认上传 |
| `draft/verified/pending` | 安全扫描排队中 | 刷新状态、查看扫描事件 |
| `draft/verified/scanning` | 安全扫描中 | 刷新状态、查看扫描事件 |
| `draft/verified/passed` | 可发布 | 发布、预览、下载 |
| `active/verified/passed` | 已发布 | 预览、下载、下架 |
| `draft/verified/failed` | 安全扫描失败 | 查看扫描事件、重新上传 |
| `draft/failed/skipped` | 上传复检失败 | 查看复检/扫描事件、重新上传 |
租户后台可通过下面接口排查扫描过程:
```http
GET /api/tenant-content/assets/security-scan-events?assetId=<assetId>&limit=100
```
`GET /api/tenant-content/assets` 和学生端 `GET /api/catalog/assets` 都会返回 `securityScanStatus`。前端可以展示状态,但最终能否下载、预览、播放仍以后端签名接口为准。
生产环境会定时运行 assets worker 复检对象存储元数据并执行内置 `metadata_rules` 安全扫描。复检发现对象丢失、跨租户 objectKey、大小/MIME/checksum 不一致时,后端会把资源置为 `uploadStatus=failed``securityScanStatus=skipped` 并从 `active` 退回 `draft`,同时写入 `securityFlags.assetRecheckFailed=true`。扫描发现 MIME 不允许、扩展名/MIME 不匹配等问题时,会把资源置为 `securityScanStatus=failed`,并写入 `securityFlags.assetSecurityScanFailed=true`。租户后台资源列表应对 failed/skipped 资源展示异常原因和重新上传入口;学生端不要缓存资料列表和签名 URL 作为长期状态。
## 考试倒计时、签到积分和反馈