在处理企业级文件上传(如发票附件、合同 PDF、报表导出)时,传统模式通常让客户端把大文件全部 POST 给 API 服务器,由服务端读入内存再转发到存储桶。 这种模式在高并发下存在致命隐患:
- API 网关被大文件打满:几十个几百兆的视频或大文件上传直接打爆应用服务器的带宽与内存;
- 凭据泄露风险:把 S3 的 Root AccessKey/SecretKey 暴露在前端客户端;
- 越权下载(IDOR):只要猜到文件的 Object Key,任何人都能随意下载其他租户的机密合同。
BitzOrcas.Modern 采用“预签名 URL 客户端直传 + 业务元数据绝对隔离”架构:服务端只签发带有短期凭据的 Presigned URL,客户端直接与 S3/MinIO 通信,服务端零带宽消耗。
预签名直传与下载安全全景
第一步:签发安全受控的预签名上传 URL
使用 IFileStorage 生成具有严格时间窗口与大小限制的上传地址:
using BitzOrcas.Application.Abstractions.Storage;using BitzOrcas.Domain.Results;
public sealed class CreateUploadSessionCommandHandler( IFileStorage fileStorage, ICurrentTenant currentTenant){ public async ValueTask<Result<UploadSessionDto>> Handle( CreateUploadSessionCommand command, CancellationToken ct) { // ① 生成防伪造的规范化 ObjectKey,包含租户隔离前缀与随机 GUID var tenantId = currentTenant.Tenant.EffectiveTenantId; var safeObjectKey = $"tenants/{tenantId}/documents/{Guid.NewGuid():N}/{command.FileName}";
// ② 签发短效预签名 PUT URL;单文件上限由 S3CompatibleStorageOptions.MaxSinglePutBytes 把守(默认 100MB) var presignedUrl = await fileStorage.GeneratePresignedUploadUrlAsync( objectKey: safeObjectKey, ttl: TimeSpan.FromMinutes(15), cancellationToken: ct);
return Result<UploadSessionDto>.Success(new UploadSessionDto(safeObjectKey, presignedUrl)); }}第二步:只读下载安全防盗链与鉴权
用户下载私有文件时,严禁向公网公开存储桶读权限。前端必须先通过 API 的业务授权,再由服务端动态签发 60 秒极短效的 GetObject 预签名地址:
public async ValueTask<Result<string>> Handle(GetFileDownloadUrlQuery query, CancellationToken ct){ // 1. 验证用户对该文件的业务访问权限(Files 模块防越权校验) var fileResult = await fileRepository.FindAsync(query.FileId, ct); if (fileResult.IsFailure) { return Result<string>.Failure(FileErrors.NotFound); }
var fileAsset = fileResult.GetValueOrThrow();
// 2. 动态生成 60 秒有效的只读下载链接 var downloadUrl = await fileStorage.GetPresignedDownloadUrlAsync(new PresignedDownloadRequest( ObjectKey: fileAsset.ObjectKey, ExpiresIn: TimeSpan.FromSeconds(60)), ct);
return Result<string>.Success(downloadUrl);}第三步:环境适配器无缝切换
Provider(FileStorage:DefaultProvider) | 注册扩展 | 适用场景 |
|---|---|---|
Local | AddBitzOrcasLocalStorage | 本地开发、无 Docker 离线测试 |
Minio | AddBitzOrcasS3CompatibleStorage | 本地容器化联调与私有云部署——与 S3 走同一 S3CompatibleFileStore,不存在独立的 MinIOConnector |
Unavailable | 默认注册的失败关闭端口 | 未配置生产存储时的稳定失败语义 |
S3 兼容层同时覆盖 AWS S3 / 阿里云 OSS / 腾讯云 COS:连接段位于 FileStorage:S3。
总结
BitzOrcas 的对象存储设计实现了高性能与安全隔离:
- API 零带宽占用:大文件直传直取 S3/MinIO;
- 租户防盗链:私有桶 + 短效预签名确保文件不越权;
- Provider 无缝切换:一套代码适配本地盘与主流云对象存储。