forked from wangziqi/gongxue-base
115 lines
4.2 KiB
Markdown
115 lines
4.2 KiB
Markdown
# 对象存储接入说明
|
||
|
||
更新时间:2026-06-22
|
||
|
||
## 目标
|
||
|
||
题库里的图片、PDF、视频、音频、资料包等媒体资源统一走 `content_assets` 台账和后端签名接口。前端不直接保存或读取云厂商密钥,也不直接拼接私有资源 URL。题目视频播放还需要经过 `POST /api/videos/play` 校验 SVIP 或视频次数权益后下发短期签名 URL。
|
||
|
||
已接入的 provider:
|
||
|
||
- `local_dev`:本地开发占位签名,便于前后端联调。
|
||
- `aliyun_oss`:阿里云 OSS 官方 Node.js SDK `signatureUrl`。
|
||
- `tencent_cos`:腾讯云 COS XML API V5 签名 URL,服务端用 Node `crypto` 实现,避免引入当前 COS Node SDK 的高危依赖。
|
||
- `supabase_storage`:Supabase Storage 官方 `createSignedUploadUrl` / `createSignedUrl` 语义。
|
||
- `external_url`:外部公开或厂商托管 URL,只允许作为已管理资源的下载地址,不支持后端直传签名。
|
||
|
||
## API
|
||
|
||
后台申请上传签名:
|
||
|
||
```text
|
||
POST /api/tenant-content/assets/sign-upload
|
||
```
|
||
|
||
后台登记资源:
|
||
|
||
```text
|
||
PUT /api/tenant-content/assets
|
||
```
|
||
|
||
学生端下载:
|
||
|
||
```text
|
||
GET /api/catalog/assets/download?assetId=...
|
||
```
|
||
|
||
学生端视频播放:
|
||
|
||
```text
|
||
POST /api/videos/play
|
||
```
|
||
|
||
后台管理员下载:
|
||
|
||
```text
|
||
POST /api/tenant-content/assets/sign-download
|
||
```
|
||
|
||
## 安全规则
|
||
|
||
- 只有租户内容维护权限用户可以申请上传签名。
|
||
- `objectKey` 默认必须以当前 `tenantId/` 开头,防止跨租户覆盖或读取。
|
||
- 禁止 `..`、反斜杠、编码斜杠等危险 object key。
|
||
- 上传会校验 MIME 类型和文件大小。
|
||
- 下载和视频播放必须先经过 API 权限判断,再下发短期签名 URL。
|
||
- 云厂商 AccessKey、SecretKey、Service Role Key 只存在服务端环境变量,不返回前端。
|
||
- `content_assets` 是资源唯一台账,前端不得绕过台账直接访问私有 bucket。
|
||
|
||
## 环境变量
|
||
|
||
通用:
|
||
|
||
```text
|
||
STORAGE_DEFAULT_PROVIDER=local_dev
|
||
STORAGE_DEFAULT_BUCKET=tenant-assets
|
||
STORAGE_PUBLIC_BASE_URL=
|
||
STORAGE_MAX_UPLOAD_BYTES=524288000
|
||
STORAGE_ALLOWED_MIME_PREFIXES=image/,video/,audio/
|
||
STORAGE_ALLOWED_MIME_TYPES=application/pdf,application/json,application/zip,application/x-zip-compressed,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/octet-stream,text/plain,text/markdown,text/csv
|
||
STORAGE_REQUIRE_TENANT_PREFIX=true
|
||
```
|
||
|
||
阿里云 OSS:
|
||
|
||
```text
|
||
ALIYUN_OSS_REGION=oss-cn-hangzhou
|
||
ALIYUN_OSS_ENDPOINT=
|
||
ALIYUN_OSS_ACCESS_KEY_ID=
|
||
ALIYUN_OSS_ACCESS_KEY_SECRET=
|
||
ALIYUN_OSS_STS_TOKEN=
|
||
ALIYUN_OSS_INTERNAL=false
|
||
```
|
||
|
||
腾讯云 COS:
|
||
|
||
```text
|
||
TENCENT_COS_REGION=ap-shanghai
|
||
TENCENT_COS_APP_ID=
|
||
TENCENT_COS_SECRET_ID=
|
||
TENCENT_COS_SECRET_KEY=
|
||
TENCENT_COS_SECURITY_TOKEN=
|
||
```
|
||
|
||
Supabase Storage:
|
||
|
||
```text
|
||
SUPABASE_STORAGE_URL=https://your-project.supabase.co/storage/v1
|
||
SUPABASE_STORAGE_SERVICE_KEY=
|
||
```
|
||
|
||
## 生产建议
|
||
|
||
- 阿里云和腾讯云生产环境优先用 STS/临时密钥或 RAM/CAM 最小权限账号。
|
||
- bucket 默认私有,公开资源也建议先经过 CDN/防盗链策略,不让前端直接持有写权限。
|
||
- 图片、PDF、视频分别设置合理的 CORS,只允许前端域名和小程序业务域名访问。
|
||
- 开启对象版本控制、生命周期、跨区域复制或定时备份,满足后续容灾要求。
|
||
- 视频资源已接入 SVIP/播放次数校验、短期签名和播放日志;生产阶段继续补转码、动态水印、CDN 防盗链和播放统计。
|
||
- 大文件上传后应由 worker 校验对象是否真实存在、大小/hash 是否匹配,再把资源状态从 `draft` 发布为 `active`。
|
||
|
||
## 官方依据
|
||
|
||
- 阿里云 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 和服务端权限控制。
|