- Replace Go (Kratos/Wire/Watermill) implementation with .NET 10 solution - Add FileSystem.slnx, Directory.Build.props and ABP module structure - Keep Docker/Jenkins/docker-compose deployment artifacts - This drops all Go sources (cmd/, internal/, api/proto) in favor of src/
133 lines
5.8 KiB
Markdown
133 lines
5.8 KiB
Markdown
# file-system
|
||
|
||
基于 **.NET 10 + ABP + FastEndpoints + MediatR + EF Core** 的文件存储微服务,提供文件上传/下载、分片上传、存储桶管理、文件夹/文件元数据管理与分享等能力。底层使用 S3 兼容存储(RustFS/MinIO)与 PostgreSQL。提供 **HTTP + gRPC 双协议**。
|
||
|
||
由原 Go/Kratos 版重写而来,功能 1:1 对齐。
|
||
|
||
## 功能特性
|
||
|
||
- ✅ **文件操作**:上传、下载、删除、列表、预签名预览(24h)、文本内容预览(10MB)
|
||
- ✅ **分片上传**:大文件分片上传(init / part / complete / abort,服务端按 PartNumber 排序)
|
||
- ✅ **存储桶管理**:创建、列表、删除
|
||
- ✅ **文件夹与元数据**:树形文件夹、文件元数据、移动、**递归 CTE 事务删除 + best-effort S3 清理**
|
||
- ✅ **分享链接**:bcrypt 密码保护、过期时间、下载次数限制
|
||
- ✅ **JWT 鉴权**:OIDC/JWKS,信 SSO 签发的 RS256 JWT
|
||
- ✅ **所有权隔离**:受保护接口以 JWT `sub` 为权威所有者,忽略请求体 `owner_id`
|
||
- ✅ **双协议**:HTTP(FastEndpoints)+ gRPC(原生 proto),共享同一套 MediatR CQRS
|
||
|
||
## 技术栈
|
||
|
||
| 类别 | 技术 |
|
||
|------|------|
|
||
| 框架 | .NET 10、ABP 10.3(模块化)、FastEndpoints 8.1(REPR)、MediatR 14(CQRS) |
|
||
| 数据 | EF Core 10 + PostgreSQL(Npgsql) |
|
||
| 存储 | AWSSDK.S3(ForcePathStyle,兼容 RustFS/MinIO) |
|
||
| 鉴权 | OIDC Authority(JWKS 自动发现) |
|
||
| 校验 | FluentValidation 12(管线自动校验) |
|
||
| 协议 | HTTP(FastEndpoints)+ gRPC(原生 proto) |
|
||
|
||
## 架构分层
|
||
|
||
```
|
||
FileSystem.Api → FastEndpoints + Middleware + ABP 模块装配 + gRPC 服务
|
||
FileSystem.Application → MediatR CQRS handlers + DTOs + Validators + 领域事件
|
||
FileSystem.Infrastructure → EF Core + DbContext + Configurations + AuditInterceptor + S3 存储
|
||
FileSystem.Domain → Entities + Interfaces + Exceptions(零外部依赖)
|
||
```
|
||
|
||
依赖:`Api → Application → Infrastructure → Domain`。ABP 模块 `[DependsOn]` 链同构 rag-backend。
|
||
|
||
## 快速开始
|
||
|
||
### 环境要求
|
||
|
||
- .NET 10 SDK
|
||
- PostgreSQL(含库 `file_system`)
|
||
- S3 兼容存储(RustFS / MinIO)
|
||
- 可访问的 SSO 服务(用于 JWKS)
|
||
|
||
### 构建运行
|
||
|
||
```bash
|
||
dotnet build
|
||
cd src/FileSystem.Infrastructure && dotnet ef migrations add Init --startup-project ../FileSystem.Api
|
||
cd src/FileSystem.Api && dotnet run # HTTP :8080, gRPC :9090
|
||
```
|
||
|
||
或 Docker:
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
服务监听:
|
||
|
||
- HTTP: `http://localhost:8080`
|
||
- gRPC: `localhost:9090`
|
||
- Swagger: `http://localhost:8080/swagger`
|
||
|
||
## 配置
|
||
|
||
运行配置在 `src/FileSystem.Api/appsettings.json`,环境变量用 `__` 分隔节覆盖(如 `S3__Endpoint` → `S3:Endpoint`)。
|
||
|
||
| 配置项 | 说明 |
|
||
|------|------|
|
||
| `Kestrel:Endpoints:Http/Grpc` | HTTP(8080, Http1)/ gRPC(9090, Http2)监听地址 |
|
||
| `Kestrel:Limits:MaxRequestBodySize` | 请求体上限(100 MiB) |
|
||
| `ConnectionStrings:Default` | PostgreSQL 连接串 |
|
||
| `S3:*` | S3 兼容端点与凭证 |
|
||
| `Jwt:Authority` | SSO 地址,框架自动发现 JWKS |
|
||
| `Jwt:RequireHttps` | 是否要求 HTTPS(开发期 false) |
|
||
|
||
## 鉴权
|
||
|
||
- 受保护接口要求请求头携带 SSO 下发的 `Authorization: Bearer <token>`(RS256)。
|
||
- 服务从 JWT 的 `sub` claim 取用户 ID 作为资源所有者;请求体的 `owner_id`/`created_by` 字段**仅 proto 兼容保留,不作为鉴权依据**。
|
||
- 公开接口(无需鉴权):`GetShareInfo`、`DownloadShare`。
|
||
- 分享下载在设置了密码时,必须通过 `password` 字段并经 bcrypt 校验。
|
||
|
||
## API 端点(24 个)
|
||
|
||
| HTTP | 路径 | 鉴权 | 说明 |
|
||
|------|------|------|------|
|
||
| POST | `/api/files/upload` | 登录 | 上传文件(multipart,≤100MiB) |
|
||
| GET | `/api/files/download` | 登录 | 下载对象 |
|
||
| GET | `/api/files/list` | 登录 | 分页列对象(默认100/上限1000) |
|
||
| GET | `/api/files/preview` | 登录 | 24h 预签名预览 URL |
|
||
| GET | `/api/files/content` | 登录 | 文本内容(≤10MB) |
|
||
| DELETE | `/api/files/delete` | 登录 | 删除对象 |
|
||
| POST | `/api/files/multipart/init` | 登录 | 开启分片会话 |
|
||
| PUT | `/api/files/multipart/part` | 登录 | 上传单片 |
|
||
| POST | `/api/files/multipart/complete` | 登录 | 合并分片 |
|
||
| POST | `/api/files/multipart/abort` | 登录 | 取消会话 |
|
||
| POST | `/api/buckets` | 登录 | 建桶 |
|
||
| GET | `/api/buckets` | 登录 | 列桶 |
|
||
| DELETE | `/api/buckets` | 登录 | 删桶 |
|
||
| POST | `/api/folders` | 登录+sub | 建文件夹(parent_id 空=根) |
|
||
| GET | `/api/folders/tree` | 登录+sub | 该用户所有文件夹 |
|
||
| GET | `/api/folders/{id}` | 登录+sub | 文件夹+子项 |
|
||
| PUT | `/api/folders/{id}` | 登录+sub | 重命名 |
|
||
| DELETE | `/api/folders/{id}` | 登录+sub | 递归删 DB 子树 + best-effort 删 S3 |
|
||
| POST | `/api/folders/{folder_id}/files` | 登录+sub | UUID key 上传到 files 桶 + 元数据 |
|
||
| POST | `/api/files/{id}/move` | 登录+sub | 移动文件(target 空=根) |
|
||
| POST | `/api/share` | 登录+sub | 建分享(bcrypt 密码/过期/次数) |
|
||
| DELETE | `/api/share/{id}` | 登录+sub | 按 id+owner 删 |
|
||
| GET | `/api/share/{token}` | **公开** | 查分享信息 |
|
||
| POST | `/api/share/{token}/download` | **公开** | 校验密码/过期/次数 → 15min 预签名 URL |
|
||
|
||
gRPC 方法同上,契约见 `src/FileSystem.Api/Protos/file.proto`。
|
||
|
||
## 错误码
|
||
|
||
| 错误 | HTTP | 含义 |
|
||
|------|------|------|
|
||
| Unauthorized | 401 | 缺少/无效 JWT |
|
||
| Forbidden | 403 | 无权访问他人资源 |
|
||
| InvalidParameter | 400 | 参数校验失败 |
|
||
| NotFound | 404 | 资源不存在 |
|
||
| AlreadyExists | 409 | 资源已存在 |
|
||
| ShareExpired | 410 | 分享已过期 |
|
||
| ShareExhausted | 410 | 分享下载次数耗尽 |
|
||
| SharePassword | 401 | 分享密码缺失或错误 |
|
||
| TooLarge | 413 | 超过单文件大小上限(100MiB) |
|