feat: verify content asset uploads

This commit is contained in:
Codex
2026-06-29 03:30:06 +08:00
parent 7c41bf525f
commit 21c0634020
13 changed files with 988 additions and 35 deletions

View File

@@ -1,6 +1,6 @@
# 对象存储接入说明
更新时间2026-06-22
更新时间2026-06-29
## 目标
@@ -22,18 +22,30 @@
POST /api/tenant-content/assets/sign-upload
```
后台登记资源:
后台登记资源草稿
```text
PUT /api/tenant-content/assets
```
后台确认上传并发布:
```text
POST /api/tenant-content/assets/confirm-upload
```
学生端下载:
```text
GET /api/catalog/assets/download?assetId=...
```
学生端预览:
```text
GET /api/catalog/assets/preview?assetId=...
```
学生端视频播放:
```text
@@ -46,12 +58,51 @@ POST /api/videos/play
POST /api/tenant-content/assets/sign-download
```
后台管理员预览:
```text
POST /api/tenant-content/assets/sign-preview
```
## 标准上传流程
后台前端上传 PDF、图片、视频或资料包时必须走下面流程
1. 调用 `POST /api/tenant-content/assets/sign-upload` 申请短期上传 URL。
2. 前端使用返回的 `upload.url``upload.headers` 直传对象存储。
3. 调用 `PUT /api/tenant-content/assets` 登记资源台账。托管对象默认进入 `status=draft``uploadStatus=pending`
4. 调用 `POST /api/tenant-content/assets/confirm-upload`由后端读取对象元数据并比对大小、MIME、SHA-256。
5. 校验通过且 `publish=true` 时,后端将资源置为 `status=active``uploadStatus=verified`
6. 学生端只能下载或预览 `active + verified` 的托管对象资源。
确认上传示例:
```json
{
"assetId": "00000000-0000-0000-0000-000000000000",
"fileSizeBytes": 4096,
"mimeType": "application/pdf",
"checksumSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"publish": true
}
```
注意:
- `local_dev` 用声明的元数据模拟对象 HEAD方便本地和集成测试。
- `aliyun_oss` 使用 OSS 对象 HEAD 元数据。
- `tencent_cos` 使用 COS HEAD Object 预签名请求读取元数据。
- `supabase_storage` 使用 Storage list metadata 做最小存在性/大小校验。
- 如果 provider 无法返回 SHA-256后端会记录 `checksumUnavailable=true`,生产建议上传时写入对象自定义元数据,例如 `x-oss-meta-sha256``x-cos-meta-sha256`
## 安全规则
- 只有租户内容维护权限用户可以申请上传签名。
- `objectKey` 默认必须以当前 `tenantId/` 开头,防止跨租户覆盖或读取。
- 禁止 `..`、反斜杠、编码斜杠等危险 object key。
- 上传会校验 MIME 类型和文件大小。
- 托管对象资源未确认前不能发布为 `active`,学生端不可下载。
- PDF/图片预览使用 `inline` 签名,不等同于长期公开 URL。
- 下载和视频播放必须先经过 API 权限判断,再下发短期签名 URL。
- 云厂商 AccessKey、SecretKey、Service Role Key 只存在服务端环境变量,不返回前端。
- `content_assets` 是资源唯一台账,前端不得绕过台账直接访问私有 bucket。
@@ -105,10 +156,10 @@ SUPABASE_STORAGE_SERVICE_KEY=
- 图片、PDF、视频分别设置合理的 CORS只允许前端域名和小程序业务域名访问。
- 开启对象版本控制、生命周期、跨区域复制或定时备份,满足后续容灾要求。
- 视频资源已接入 SVIP/播放次数校验、短期签名和播放日志生产阶段继续补转码、动态水印、CDN 防盗链和播放统计。
- 大文件上传后应由 worker 校验对象是否真实存在、大小/hash 是否匹配,再把资源状态从 `draft` 发布为 `active`
- 大文件上传已经支持 API 即时确认;后续可增加 worker 做异步复检、杀毒、转码、水印和 CDN 刷新
## 官方依据
- 阿里云 OSS Node.js SDK 支持通过 `signatureUrl` 为上传下载生成带过期时间的签名 URL。
- 腾讯云 COS XML API V5 签名由 `q-sign-algorithm``q-ak``q-sign-time``q-key-time``q-header-list``q-url-param-list``q-signature` 等字段组成,可用于预签名 URL。
- Supabase Storage 提供 `createSignedUploadUrl``createSignedUrl`,分别用于签名上传和签名下载;私有 bucket 仍应配合 RLS服务端权限控制。
- 阿里云 OSS Node.js SDK 支持通过 `signatureUrl` 为上传/下载生成带过期时间的签名 URL,并可通过对象 HEAD 读取元数据
- 腾讯云 COS XML API V5 签名由 `q-sign-algorithm``q-ak``q-sign-time``q-key-time``q-header-list``q-url-param-list``q-signature` 等字段组成,可用于预签名 URL 和 HEAD Object
- Supabase Storage 提供 `createSignedUploadUrl``createSignedUrl`,分别用于签名上传和签名下载;私有 bucket 仍应配合 RLS服务端权限控制和资源台账