feat(handler): add app

This commit is contained in:
2026-01-31 15:44:56 +08:00
parent 6b68a368f1
commit 4dc46659c9
25 changed files with 2516 additions and 14 deletions

129
docs/APP_API.md Normal file
View File

@@ -0,0 +1,129 @@
# App 生命周期管理接口(平台级)
本模块用于维护“允许的 App 注册表apps并提供应用上下线审批含生效时间与审计记录能力。
## 权限与访问级别
本模块所有接口均为平台级接口:
- URL 前缀:`/platform`
- 认证:`Authorization: Bearer <access_token>`
- 权限:平台权限(系统角色 `SuperAdmin`)校验
权限码:
- `iam:app:read`:查询 apps 与审批单
- `iam:app:write`:创建/更新 apps、提交上下线申请
- `iam:app:approve`:审批上下线申请
- `iam:app:delete`删除软删除app
## 通用响应结构
成功:
```json
{ "code": 0, "message": "Success|Created", "data": {}, "trace_id": null }
```
错误(示例):
```json
{ "code": 20003, "message": "Permission denied: iam:app:read", "details": null, "trace_id": null }
```
常见错误码:
- 20000/20006未认证缺少 Authorization
- 20003无权限缺少平台权限码
- 30000参数错误格式/长度/取值非法)
- 30002资源不存在app / request_id 不存在)
- 30003资源冲突app_id 重复)
## 1) 新增 App
**POST** `/platform/apps`
Body
- `id`应用标识符2~32`[a-z0-9_-]`,建议小写,如 `cms`/`tms`
- `name`:名称(必填,<=100
- `description`:描述(可选)
- `app_type`:类型(可选,默认 `generic`,建议小写短标识)
- `owner`:负责人/团队(可选,<=100
示例:
```bash
curl -X POST "http://127.0.0.1:3000/platform/apps" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "id":"dms","name":"DMS","description":"Document","app_type":"product","owner":"team-a" }'
```
## 2) 查询 App 列表(分页/筛选/排序)
**GET** `/platform/apps`
Query
- `page`:默认 1
- `page_size`:默认 20范围 1..=200
- `status`:可选(`active|disabled|deleted`
- `app_type`:可选
- `created_from` / `created_to`可选RFC3339
- `sort_by``id|name|status|app_type|created_at|updated_at`(默认 `created_at`
- `sort_order``asc|desc`(默认 `desc`
## 3) 查询 App 详情
**GET** `/platform/apps/{app_id}`
## 4) 更新 App 基础信息
**PATCH** `/platform/apps/{app_id}`
Body全部可选
- `name`
- `description`
- `app_type`
- `owner`
## 5) 申请 App 上下线(审批 + 生效时间)
**POST** `/platform/apps/{app_id}/status-change-requests`
Body
- `to_status``active|disabled`
- `effective_at`可选RFC3339不填表示审批后立即生效
- `reason`:可选
说明:
- 新建审批单初始 `status=pending`
- 审批通过后:
-`effective_at` 为空或已到达,则自动应用并把审批单状态置为 `applied`
-`effective_at` 在未来,则审批单状态为 `approved`,在后续列表/查询时会尝试自动应用到期变更
## 6) 查询审批单列表
**GET** `/platform/app-status-change-requests`
Query
- `status`:可选(`pending|approved|applied|rejected`
- `page` / `page_size`
## 7) 审批通过 / 驳回
通过:
**POST** `/platform/app-status-change-requests/{request_id}/approve`
Body
- `effective_at`:可选(用于覆盖/补充生效时间)
驳回:
**POST** `/platform/app-status-change-requests/{request_id}/reject?reason=...`
## 8) 删除 App软删除
**DELETE** `/platform/apps/{app_id}`
说明:
- 软删除会将 `apps.status` 标记为 `deleted`
- 若设置环境变量 `IAM_SENSITIVE_ACTION_TOKEN`,必须同时提供 Header`X-Sensitive-Token: <token>`

53
docs/PERF_TEST.md Normal file
View File

@@ -0,0 +1,53 @@
# 性能压测说明App 管理接口)
本仓库默认不携带外部压测工具(如 wrk/oha/hey因此提供“可复现的压测方法 + 指标口径 + 建议阈值”,并建议在 CI/CD 或预发环境执行并归档结果。
## 1) 压测对象
- `GET /platform/apps`:分页列表(典型读流量)
- `POST /platform/apps`:创建(写流量)
- `POST /platform/apps/{app_id}/status-change-requests`:写流量
## 2) 指标口径
- 吞吐RPS
- 延迟p50 / p95 / p99
- 错误率:非 2xx 比例
- 资源CPU / 内存 / DB 连接池占用
## 3) 环境准备
- 数据库完成迁移:`./scripts/db/migrate.sh && ./scripts/db/verify.sh`
- 用平台租户 token 作为压测 token必须具备 `iam:app:read` 等权限)
- 建议在压测前预填充一定数量 apps如 1k/10k
## 4) 示例wrk
若环境已安装 `wrk`
```bash
wrk -t4 -c32 -d30s \\
-H "Authorization: Bearer <token>" \\
"http://127.0.0.1:3000/platform/apps?page=1&page_size=20"
```
## 5) 示例(纯 curl 简易压测)
该方式不统计精确吞吐与分位数,但可快速验证稳定性与错误率:
```bash
for i in $(seq 1 200); do
curl -s -o /dev/null -w "%{http_code}\\n" \\
-H "Authorization: Bearer <token>" \\
"http://127.0.0.1:3000/platform/apps?page=1&page_size=20" &
done
wait
```
## 6) 建议阈值(参考)
- `GET /platform/apps`p95 < 100ms本机/ AZ错误率 < 0.1%
- `POST /platform/apps`p95 < 200ms错误率 < 0.1%
实际阈值应结合数据库规模索引网关链路与部署规格确定

View File

@@ -77,6 +77,8 @@
- Tag`Tenant`
- Header
- 二次验证(可选但建议生产启用):
- 若设置环境变量 `IAM_SENSITIVE_ACTION_TOKEN`,则必须传 Header`X-Sensitive-Token: <token>`,否则返回 403。
- Body
```json
@@ -212,6 +214,82 @@ enabled_apps 维护建议:
- 下线应用:将 `apps.status` 置为非 `active`(例如 `disabled`),之后将无法再被设置进任何租户的 enabled_apps。
- 查询可用应用(示例 SQL`SELECT id, name, status FROM apps ORDER BY id;`
### Step 4.2:平台层 App 生命周期管理SuperAdmin
用于维护“允许的 App 注册表”,并提供应用上下线(审批 + 生效时间)能力。
权限要求(平台级):
- `iam:app:read`
- `iam:app:write`
- `iam:app:approve`
- `iam:app:delete`
#### 4.2.1 新增 App
**POST** `/platform/apps`
- Tag`App`
- Header`Authorization: Bearer <access_token>`(平台租户下登录得到的 token
- Body示例
```json
{ "id": "dms", "name": "DMS", "description": "Document Management System", "app_type": "product", "owner": "team-a" }
```
#### 4.2.2 查询 App 列表(分页/筛选/排序)
**GET** `/platform/apps?page=1&page_size=20&status=active&app_type=product&sort_by=created_at&sort_order=desc`
- Tag`App`
- Header`Authorization: Bearer <access_token>`
#### 4.2.3 更新 App 基础信息
**PATCH** `/platform/apps/{app_id}`
- Tag`App`
- Header`Authorization: Bearer <access_token>`
- Body示例
```json
{ "description": "DMS v2", "owner": "team-b" }
```
#### 4.2.4 申请 App 上下线(需要审批,可设置生效时间)
**POST** `/platform/apps/{app_id}/status-change-requests`
- Tag`App`
- Header`Authorization: Bearer <access_token>`
- Body示例立即禁用
```json
{ "to_status": "disabled", "reason": "security patch" }
```
- Body示例延迟生效
```json
{ "to_status": "disabled", "effective_at": "2026-02-01T00:00:00Z", "reason": "maintenance window" }
```
#### 4.2.5 审批上下线申请单
**GET** `/platform/app-status-change-requests?status=pending&page=1&page_size=20`
**POST** `/platform/app-status-change-requests/{request_id}/approve`
**POST** `/platform/app-status-change-requests/{request_id}/reject?reason=...`
#### 4.2.6 删除 App软删除
**DELETE** `/platform/apps/{app_id}`
- Tag`App`
- Header`Authorization: Bearer <access_token>`
- 二次验证(可选但建议生产启用):
- 若设置环境变量 `IAM_SENSITIVE_ACTION_TOKEN`,则必须同时传 Header`X-Sensitive-Token: <token>`,否则返回 403。
### Step 5列出用户User
**GET** `/users?page=1&page_size=20`
@@ -272,3 +350,25 @@ enabled_apps 维护建议:
- `/auth/login`:约 2 req/sburst 10同一 IP
- `/auth/register`:约 1 req/sburst 5同一 IP
- 触发后返回HTTP 429 + `code=40000`
## 密码重置User
用户自助重置(需要旧密码):
- **POST** `/users/me/password/reset`
- Tag`User`
- Header`Authorization: Bearer <access_token>`
- Body
```json
{ "current_password": "oldPassword123", "new_password": "newPassword456" }
```
租户管理员重置任意用户(生成临时密码):
- **POST** `/users/{id}/password/reset`
- Tag`User`
- Header`Authorization: Bearer <access_token>`
- 权限:需要 `user:password:reset:any`
- 二次验证(可选但建议生产启用):
- 若设置环境变量 `IAM_SENSITIVE_ACTION_TOKEN`,则必须传 Header`X-Sensitive-Token: <token>`,否则返回 403。

View File

@@ -0,0 +1,90 @@
# 安全评估与接口治理建议IAM Service
本文面向本仓库当前实现,给出“暴露面审查、风险识别、接口分级、敏感操作二次验证、隐藏策略”建议,并标注已落地的控制点。
## 1) 当前接口暴露面概览(按访问级别)
### 公开接口Public
特点:无需 Bearer Token可被外部直接调用应最小化
- `POST /tenants/register`:创建租户
- `POST /auth/register`:租户内注册用户(依赖 Header `X-Tenant-ID`
- `POST /auth/login`:租户内登录(依赖 Header `X-Tenant-ID`
- `GET /scalar`OpenAPI/Scalar 文档
### 认证接口Authenticated
特点:要求 Bearer Token应默认通过网关/WAF 暴露。
- `GET /tenants/me``PATCH /tenants/me``DELETE /tenants/me`
- `POST /tenants/me/status`
- `GET /me/permissions`
- `GET/PATCH/DELETE /users...``GET/PUT /users/{id}/roles`
- `GET/POST /roles`
### 内部/平台接口Internal / Platform
特点平台权限系统角色才能访问建议网关层做更严格限制IP allowlist、mTLS、独立域名等
- `GET/PUT /platform/tenants/{tenant_id}/enabled-apps`
- `GET/POST /platform/apps``GET/PATCH/DELETE /platform/apps/{app_id}`
- `POST /platform/apps/{app_id}/status-change-requests`
- `GET /platform/app-status-change-requests`
- `POST /platform/app-status-change-requests/{request_id}/approve|reject`
## 2) 风险识别(重点)
- **租户创建为公开接口**:可能被滥用批量创建租户,造成资源耗尽、审计噪声、后续越权风险面扩大。
- **注册为公开接口**:对任意租户 ID 可注册用户(虽然要求 `X-Tenant-ID`,但租户 ID 可被枚举/泄露)。
- **平台接口暴露风险**:即便有平台权限控制,一旦 token 泄露将影响全局enabled_apps 与 apps 注册表)。
- **文档暴露**`/scalar` 默认公开,可能暴露内部接口与参数细节。
## 3) 已落地控制点(本次实现)
- **敏感操作二次验证(可选开关)**
- 通过环境变量 `IAM_SENSITIVE_ACTION_TOKEN` 启用二次验证。
- 当启用时,下列操作必须额外携带 Header `X-Sensitive-Token: <token>`
- `POST /tenants/register`
- `DELETE /platform/apps/{app_id}`
- 目的:降低“单一 Bearer Token 泄露”或“误调用”带来的破坏面。
- **平台权限细分**
- apps 生命周期管理引入平台权限码:`iam:app:read|write|approve|delete`
- enabled_apps 管理权限码:`iam:tenant:enabled_apps:read|write`
## 4) 建议的接口分级制度(治理)
建议把接口按“公开 / 认证 / 内部平台”分级,并在网关与代码侧同时落实:
- Public公开
- 强制:限流、验证码/人机校验可选、IP 风控、灰度开关、审计
- 建议:对 `tenants/register` 改为“邀请制/工单制”,或迁移到平台后台
- Authenticated认证
- 强制:最小权限、全链路审计、错误码统一、分页上限、输入校验
- Internal / Platform内部
- 强制:网关层隔离(独立域名/路由、mTLS 或 IP allowlist、更严格限流、短 TTL token、专用账号
- 建议:默认不在公开文档展示(需要登录后才能看到或独立文档入口)
## 5) 接口隐藏策略建议(不改变业务语义)
- 网关层
- 路由隔离:`/platform/*` 走独立 upstream 或仅内网可达
- 访问控制IP allowlist、mTLS、JWT audience/issuer 分离
- 速率限制:对平台接口与租户创建设置更低阈值
- 版本管理
- 对内部平台接口采用独立版本前缀:如 `/platform/v1/...`
- 对外接口保持稳定;内部接口可快速迭代
- 文档权限
-`/scalar` 拆分为 public 与 internal 两份,或对 internal 文档加登录保护
## 6) 下一步改造建议(按风险优先级)
1.`POST /tenants/register` 从公开接口迁移为平台接口(或邀请制),并引入更强风控。
2.`POST /auth/register` 引入租户级注册策略(开关、邀请、允许域名白名单等)。
3.`/platform/*` 接口在网关实现“物理隔离”(内网 + mTLS而不仅是逻辑权限校验。

44
docs/TEST_REPORT.md Normal file
View File

@@ -0,0 +1,44 @@
# 测试报告App 生命周期管理)
## 1) 目标与范围
覆盖本次新增的 App 生命周期管理能力:
- app id/name/type 等输入校验与清洗
- apps 注册表的创建/更新/查询
- 上下线审批(申请/审批/生效)
- 软删除
## 2) 测试类型
### 单元测试(无需数据库)
- `src/services/app.rs`:包含 app_id 等关键字段校验用例
### 集成/冒烟测试(需要 DATABASE_URL
当设置 `DATABASE_URL` 时会执行:
- `tests/enabled_apps_smoke.rs`enabled_apps 读写与版本冲突
- `tests/app_lifecycle_smoke.rs`apps 创建/更新/审批禁用/软删除
若未设置 `DATABASE_URL`,上述集成测试会自动跳过(返回 Ok
## 3) 执行方式
```bash
cargo test
```
若要执行集成测试,需提供可用的 PostgreSQL 连接串,并保证已完成迁移:
```bash
export DATABASE_URL='postgres://...'
./scripts/db/migrate.sh
./scripts/db/verify.sh
cargo test
```
## 4) 结果说明
- 已在当前仓库执行 `cargo test`,测试通过。
- 代码仓库内测试已保持可重复执行,并在无数据库时不阻塞开发体验。
- 覆盖率统计需依赖覆盖率工具(如 cargo-llvm-cov 或 tarpaulin本仓库当前未内置该工具链。