2.5 KiB
2.5 KiB
5.9 多租户隔离
:::tip 概述
租户隔离是双侧执行的红线:写侧全局 Create 钩子补齐 tenant_id,读侧 repository Scope 追加租户条件。判定依据是 hooks.tenantTables 白名单(9 张表),租户状态由租户中间件在请求入口校验。
:::
隔离模型
平台级(tenantID=0,超管) → 不过滤,全量可见
租户用户 → tenant_id IN (0, 自身租户)
(0 为平台级公共数据,租户可见)
双侧执行
| 侧 | 执行点 | 行为 |
|---|---|---|
| 写 | Create 钩子(createStamp) | 租户用户未指定时强制携带自身租户(防跨租户逃逸);超管未指定时取 tenant.defaultId,显式传 0 可创建平台共享行 |
| 读 | repository Scope(ApplyCtx) | 租户表追加 tenant_id IN (0, 自身租户) |
业务代码零参与——只要走 Ctx(ctx),隔离自动生效。
租户白名单(9 张表)
gin_user / gin_role / gin_dept / gin_level / gin_position
gin_article / gin_category / gin_notice / gin_link
新增租户级表必须同步登记 internal/model/hooks 的 tenantTables——漏登记的表写侧不带租户ID、读侧不过滤,等于隔离失效。表还需要真实存在 tenant_id 列。
租户中间件
链位置:JWT 之后、Authz 之前。校验逻辑:
免登录 → 放行
平台级(tenantID=0)→ 放行
租户摘要(缓存 60 秒):
状态非 1(禁用)→ 拒绝
过期时间早于当前 → 拒绝
摘要加载失败 / 加载器未注册 → 放行(降级:不因租户设施故障阻断全部请求)
登录时的租户定位
登录请求可带 tenantCode:指定时在租户内定位用户;留空时全局匹配(优先平台租户)。租户不存在/禁用/过期分别返回对应业务错误码。
租户管理能力
- 租户 CRUD(gin_tenant,平台级表)
- 租户状态启停、有效期管理
- 超管新增租户级数据的默认归属(
tenant.defaultId)
管理界面见 6.7 租户管理。
设计边界
| 在租户隔离内 | 不在租户隔离内 |
|---|---|
| 白名单 9 张表的常规读写 | 字典、参数、配置等平台级表 |
| 在线用户列表/强退(按租户过滤) | 日志表(审计归属平台) |
| 内容模块(文章/分类/公告/友链) | 示例表 gin_example |