Files
iam-service/docs/AUTHZ_DESIGN.md
2026-01-30 16:31:53 +08:00

88 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 权限控制架构设计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 作为数据库兜底隔离层。