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

3.8 KiB
Raw Blame History

权限控制架构设计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”的折中

  • 规则源Servicesrc/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 作为数据库兜底隔离层。