232 lines
8.1 KiB
Markdown
232 lines
8.1 KiB
Markdown
# iam-service(多租户 IAM 服务)
|
||
|
||
一个基于 Rust 的多租户身份识别与访问管理(IAM)服务雏形,当前已提供“租户隔离 + 用户注册/登录 + 基础租户管理 + 基于 JWT 的认证中间件 + RBAC 权限校验骨架”能力,并为后续扩展 MFA/SSO、Token 刷新/吊销、ABAC 策略引擎等功能预留了模块边界。
|
||
|
||
## 技术栈
|
||
|
||
- 语言与运行时:Rust(edition 2024)、Tokio
|
||
- Web:Axum
|
||
- 数据库:PostgreSQL + SQLx
|
||
- 密码:Argon2
|
||
- Token:JWT(RS256 非对称签发/验签已实现;JWK Set 端点待补齐)
|
||
- 可观测性:tracing + `common-telemetry`(私有 registry:kellnr)
|
||
- API 文档:utoipa + Scalar(`/scalar`)
|
||
|
||
## 系统架构
|
||
|
||
### 请求链路(当前)
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
C[Client] -->|HTTP + JSON| R[Axum Router]
|
||
R --> A[认证中间件 authenticate]
|
||
A --> M[租户中间件 resolve_tenant]
|
||
M --> H[Handlers + RBAC 校验]
|
||
H --> S[Services]
|
||
S --> DB[(PostgreSQL)]
|
||
|
||
H --> O[统一错误 AppError]
|
||
R --> D[OpenAPI/Scalar /scalar]
|
||
```
|
||
|
||
### 多租户实现方式
|
||
|
||
当前采用“共享数据库 + 共享表,通过 `tenant_id` 区分”的模式:
|
||
|
||
- `users.tenant_id` 外键引用 `tenants.id`(强制用户必须归属某个租户)
|
||
- `users(tenant_id, email)` 联合唯一索引(同租户邮箱唯一,不同租户可重复)
|
||
- HTTP 层优先通过 `Authorization: Bearer <access_token>` 中的 `tenant_id` claim 传入租户上下文,并在 Service/SQL 查询中使用 `tenant_id` 过滤
|
||
- 兼容:仍支持请求头 `X-Tenant-ID: <uuid>`,若同时提供 Header 与 Token,将强制校验两者一致,否则返回 403
|
||
|
||
## 项目结构说明
|
||
|
||
- [src/main.rs](file:///home/shay/project/backend/iam-service/src/main.rs):服务入口、路由组装、Telemetry 初始化、DB 连接池初始化
|
||
- [src/config/mod.rs](file:///home/shay/project/backend/iam-service/src/config/mod.rs):环境变量配置加载
|
||
- [src/db/mod.rs](file:///home/shay/project/backend/iam-service/src/db/mod.rs):PostgreSQL 连接池初始化(迁移功能目前未启用)
|
||
- [src/middleware/mod.rs](file:///home/shay/project/backend/iam-service/src/middleware/mod.rs):多租户中间件与 `TenantId` 提取器
|
||
- [src/middleware/auth.rs](file:///home/shay/project/backend/iam-service/src/middleware/auth.rs):JWT 认证中间件与 `AuthContext` 提取器
|
||
- [src/handlers/mod.rs](file:///home/shay/project/backend/iam-service/src/handlers/mod.rs):HTTP Handler(控制器层),负责参数解析、调用 Service、返回统一响应
|
||
- [src/services/mod.rs](file:///home/shay/project/backend/iam-service/src/services/mod.rs):业务逻辑(注册/登录)与数据库交互
|
||
- [src/models.rs](file:///home/shay/project/backend/iam-service/src/models.rs):DB Model 与请求/响应 DTO(同时用于 OpenAPI Schema)
|
||
- [src/utils/mod.rs](file:///home/shay/project/backend/iam-service/src/utils/mod.rs):密码哈希与 JWT 签发工具
|
||
- [sql/schema_post_init.sql](file:///home/shay/project/backend/iam-service/sql/schema_post_init.sql):Schema 初始化(DDL+DML,适用于开发/测试)
|
||
- [scripts/db/rebuild_iam_db.sh](file:///home/shay/project/backend/iam-service/scripts/db/rebuild_iam_db.sh):一键重建 schema(可选备份+DROP+重建+校验)
|
||
- [docs/DB_PROVISIONING.md](file:///home/shay/project/backend/iam-service/docs/DB_PROVISIONING.md):数据库/用户创建与 schema 初始化说明(归档)
|
||
|
||
## 快速开始
|
||
|
||
### 环境要求
|
||
|
||
- Rust:支持 edition 2024 的版本(建议使用最新 stable)
|
||
- PostgreSQL:建议 14+
|
||
|
||
### 安装与运行
|
||
|
||
1. 克隆仓库并进入目录
|
||
|
||
```bash
|
||
git clone <your-repo-url>
|
||
cd iam-service
|
||
```
|
||
|
||
2. 初始化数据库(开发/测试示例)
|
||
|
||
```bash
|
||
export DATABASE_URL='postgres://iam_service_user:***@<pg_host>:5432/iam_service_db'
|
||
BACKUP=1 ./scripts/db/rebuild_iam_db.sh
|
||
```
|
||
|
||
3. 配置环境变量
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
按需修改 `.env`:
|
||
|
||
- `DATABASE_URL`:PostgreSQL 连接串
|
||
- `JWT_SECRET`:保留字段(当前 RS256 实现未使用;后续将用于密钥加载/加密存储)
|
||
- `PORT`:监听端口
|
||
|
||
4. 启动服务
|
||
|
||
```bash
|
||
cargo run
|
||
```
|
||
|
||
启动后:
|
||
|
||
- 服务地址:`http://127.0.0.1:<PORT>`
|
||
- API 文档:`http://127.0.0.1:<PORT>/scalar`
|
||
|
||
## 核心功能与 API
|
||
|
||
### 租户注册
|
||
|
||
`POST /tenants/register`
|
||
|
||
```bash
|
||
curl -X POST "http://127.0.0.1:3000/tenants/register" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"name":"Tenant A","config":{"theme":{"primary":"#1d4ed8"}}}'
|
||
```
|
||
|
||
返回(示例):
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "Created",
|
||
"data": {
|
||
"id": "22222222-2222-2222-2222-222222222222",
|
||
"name": "Tenant A",
|
||
"status": "active",
|
||
"config": { "theme": { "primary": "#1d4ed8" } }
|
||
},
|
||
"trace_id": null
|
||
}
|
||
```
|
||
|
||
### 用户注册
|
||
|
||
`POST /auth/register`(需要请求头 `X-Tenant-ID`)
|
||
|
||
```bash
|
||
curl -X POST "http://127.0.0.1:3000/auth/register" \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Tenant-ID: 11111111-1111-1111-1111-111111111111" \
|
||
-d '{"email":"user@example.com","password":"securePassword123"}'
|
||
```
|
||
|
||
返回(示例):
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "Created",
|
||
"data": {
|
||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
"email": "user@example.com"
|
||
},
|
||
"trace_id": null
|
||
}
|
||
```
|
||
|
||
### 登录
|
||
|
||
`POST /auth/login`(需要请求头 `X-Tenant-ID`)
|
||
|
||
```bash
|
||
curl -X POST "http://127.0.0.1:3000/auth/login" \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Tenant-ID: 11111111-1111-1111-1111-111111111111" \
|
||
-d '{"email":"user@example.com","password":"securePassword123"}'
|
||
```
|
||
|
||
返回(示例):
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "Success",
|
||
"data": {
|
||
"access_token": "<jwt>",
|
||
"refresh_token": "<opaque>",
|
||
"token_type": "Bearer",
|
||
"expires_in": 900
|
||
},
|
||
"trace_id": null
|
||
}
|
||
```
|
||
|
||
### 租户信息维护(需要鉴权 + 权限)
|
||
|
||
- `GET /tenants/me`(需要 `tenant:read`)
|
||
- `PATCH /tenants/me`(需要 `tenant:write`)
|
||
- `POST /tenants/me/status`(需要 `tenant:write`)
|
||
- `DELETE /tenants/me`(需要 `tenant:write`)
|
||
|
||
调用示例:
|
||
|
||
```bash
|
||
curl -X GET "http://127.0.0.1:3000/tenants/me" \
|
||
-H "Authorization: Bearer <access_token>"
|
||
```
|
||
|
||
## 权限控制(当前实现方式)
|
||
|
||
- 认证(Authentication):在中间件层完成([auth.rs](file:///home/shay/project/backend/iam-service/src/middleware/auth.rs)),统一解析 `Authorization`,验签 JWT,并注入 `AuthContext`。
|
||
- 租户上下文(Tenant Context):在中间件层完成([mod.rs](file:///home/shay/project/backend/iam-service/src/middleware/mod.rs)),优先使用 `AuthContext.tenant_id`,并兼容 `X-Tenant-ID`(强制一致性校验)。
|
||
- 授权(Authorization / RBAC):在 Handler 层作为请求级拦截点调用 Service([authorization.rs](file:///home/shay/project/backend/iam-service/src/services/authorization.rs)),把“查库/规则”放在 Service 层,避免 Handler 直接拼 SQL。
|
||
|
||
更完整的“RBAC + ABAC 混合模型”落地建议见 [AUTHZ_DESIGN.md](file:///home/shay/project/backend/iam-service/AUTHZ_DESIGN.md)。
|
||
|
||
## 限流(生产建议)
|
||
|
||
- 登录/注册已在路由级挂载限流(见 [rate_limit.rs](file:///home/shay/project/backend/iam-service/src/middleware/rate_limit.rs))。
|
||
- 生产推荐在网关/边缘层做全局限流与 Bot 防护,服务内限流作为兜底。
|
||
- 可信代理模式:
|
||
- 配置 `TRUSTED_PROXY_CIDRS`,仅当对端连接 IP 命中这些网段时,才信任 `Forwarded` / `X-Forwarded-For` / `X-Real-IP` 提取真实客户端 IP 进行限流。
|
||
- 未命中可信代理时,将忽略这些 Header,退回按对端连接 IP 限流,避免 Header 伪造绕过。
|
||
|
||
## 部署指南
|
||
|
||
### 本地/测试环境
|
||
|
||
- 使用 `.env` 配置连接串、端口、日志等
|
||
- 直接运行:`cargo run`
|
||
|
||
### 生产环境(建议)
|
||
|
||
- 构建:`cargo build --release`
|
||
- 以环境变量方式注入 `DATABASE_URL/JWT_SECRET/...`,避免把 `.env` 放入镜像或仓库
|
||
- 使用反向代理(Nginx/Envoy)处理 TLS、限流与审计日志(视需求)
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
cargo test
|
||
```
|
||
|
||
当前仓库尚未包含单元测试/集成测试用例;建议在新增登录、鉴权与授权功能时补充覆盖(尤其是租户隔离与权限边界)。
|