fix(handlers): add handlers

This commit is contained in:
2026-01-30 16:31:53 +08:00
parent bb82c75834
commit ce12b997f4
38 changed files with 3746 additions and 317 deletions

87
docs/AUTHZ_DESIGN.md Normal file
View File

@@ -0,0 +1,87 @@
# 权限控制架构设计Tenant-User-Role
## 目标
- 保证租户隔离:任何用户只能访问其 Token 绑定的租户数据
- 保证授权一致:同一类请求在所有入口都遵循同样的鉴权与授权规则
- 保证可演进RBAC 可以稳定运行ABAC 可逐步引入策略引擎与审计闭环
## 分层职责与落点
### 认证Authentication中间件层
- 位置:`src/middleware/auth.rs`
- 输入:`Authorization: Bearer <access_token>`
- 输出:解析/验签 Token 并注入 `AuthContext { tenant_id, user_id, roles, permissions }`
- 选择理由:
- 认证属于横切关注点,放在中间件可避免每个 Handler 重复实现
- 401/403 与错误码可统一,便于网关与客户端处理
- 便于埋点在统一入口记录审计字段IP/UA/结果/耗时)
### 租户上下文Tenant Context中间件层
- 位置:`src/middleware/mod.rs`
- 行为:
- 优先使用 `AuthContext.tenant_id` 注入 `TenantId`
- 兼容 `X-Tenant-ID`,若 Header 与 Token 同时存在则强制一致,否则返回 403
- 选择理由:
- 租户隔离是安全边界,必须在最靠前的入口稳定执行,避免业务分支遗漏
### 授权AuthorizationService 层为规则源Handler/中间件为拦截点
当前实现采用“规则在 Service、拦截在 Handler”的折中
- 规则源Service`src/services/authorization.rs`
- 负责 RBAC 查库:用户→角色→权限
- 产出统一决策(允许/拒绝)并返回 `AppError::PermissionDenied`
- 拦截点Handler在具体接口中调用 `AuthorizationService::require_permission(...)`
- 选择理由:
- Handler 更接近“路由-动作”语义,决定某个接口需要什么权限更直观
- Service 只负责“如何判断”,不关心“哪个路由需要什么”
当路由数量增长后,建议演进为“拦截点上移到中间件/Layer”
- 给不同 Router 分组挂载不同的授权 Layer如 tenant 管理、用户管理、角色管理)
- 或引入宏/属性(例如 `#[require("tenant:write")]`)生成统一的 Guard
### ABAC建议落点后续实现
ABAC 需要资源属性、环境属性、请求属性,通常依赖:
- 资源属性DB 查询或缓存读取(属于业务领域)
- 环境属性IP、时间、设备风险、地理位置属于安全/风控)
- 请求属性:请求参数与上下文字段
因此 ABAC 的“策略评估”建议由独立模块/服务承担(例如 `PolicyEngine`),并由 Handler 在调用业务 Service 之前完成决策;决策审计由统一审计组件记录。
## 审计与可观测性
- 建议在认证/授权路径内记录审计事件:
- actortenant_id、user_id
- decisionallow/deny
- policy匹配的 RBAC 权限或 ABAC 策略 ID
- cost授权耗时
- 当前库 `common-telemetry` 已提供统一错误返回;建议后续在错误响应中补齐 trace_id从 tracing context 获取)。
## 数据隔离方案对比(建议)
### 现状共享库共享表tenant_id 过滤)
- 优点:实现简单、性能可控、易于水平扩容
- 风险:任何遗漏 `tenant_id` 条件都可能造成越权
- 现有防线:
- 中间件注入 `TenantId`
- Service 查询必须显式绑定 tenant_id
### 演进方案 A独立 Schema每租户一个 schema
- 优点:逻辑隔离更强,可按租户迁移/清理
- 缺点:管理成本高,连接池与迁移复杂
### 演进方案 BPostgres Row-Level SecurityRLS
- 优点:隔离在数据库层兜底,减少“遗漏 where tenant_id”的风险
- 缺点:策略配置复杂,需要设置 session 变量(如 `app.tenant_id`)并在连接池层保证一致
建议:当租户数量增长或合规要求上升时,引入 RLS 作为数据库兜底隔离层。