ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GoWind Admin|风行 — 开箱即用的企业级全栈中后台框架:多租户与行级数据隔离

GoWind Admin|风行 — 开箱即用的企业级全栈中后台框架:多租户与行级数据隔离 GoWind Admin风行 — 开箱即用的企业级全栈中后台框架多租户与行级数据隔离SaaS 化的第一道坎就是数据隔离租户 A 的运营人员绝不能看到租户 B 的一行数据——这不是前端藏好按钮能解决的事而是要从 HTTP 入口一路压实到 SQL 的 WHERE 子句。多数自研方案的做法是在每个查询里手写tenant_id条件写漏一处就是一次数据泄露事故。风行GoWind Admin把租户隔离做成了编译进数据访问层的默认行为查询自动注入租户谓词、跨租户变更必扑空、伪造租户 ID 直接被覆盖配合 HTTP 层的 Api 表闸门形成纵深防御。本文拆解这套隔离体系的三道防线与覆盖边界。一、租户模型与上下文链路每个带租户维度的表都有tenant_id列ent mixin 装配业务开发者声明一次即可。请求进入后端后认证中间件从已验签的 JWT 构建ViewerContext租户 ID 平台/系统上下文标志作为后续所有隔离判定的唯一依据平台管理员tenant_id0跨租户可见用于运营管理租户用户所有数据访问自动被裁剪到本租户。租户与套餐的绑定由平台管理员在「租户管理」页维护租户侧用户看到的数据范围由各层自动裁剪业务代码无需也无法手动传递租户 ID。二、第一道防线HTTP 层 Api 表闸门每个租户请求在进入业务逻辑之前按路由模板method查Api 表接口注册表含模块归属命中且该租户套餐允许该模块→ 放行到业务未命中表里没这行或套餐不允许 →fail-closed 403。注意fail-closed这个取向接口没登记进 Api 表的后果是拒绝服务而不是意外放行。对多租户系统来说这是唯一正确的默认——新增端点忘记登记损失的是功能可用性而不是数据安全。两个运维要点Api 表仅在空表时由启动期从内嵌 OpenAPI 文档自动同步已部署实例新增端点后需在管理页「接口管理 → 接口同步」手动触发全量重建“平台管理员测通了≠租户测通了”——平台上下文不走这道闸门验收必须拿租户账号测。三、第二道防线数据层读写全形态隔离这是整个体系最核心的部分。风行没有采用业务代码自觉带租户条件的约定式隔离而是把隔离编译进 ent 生成的数据访问代码查询自动注入谓词。所有租户表的查询自动追加tenant_id viewer tid业务代码里写的client.User.Query().All(ctx)天然只返回本租户用户。变更全形态覆盖。Update/UpdateOne/Delete/DeleteOne 的 WHERE 恒含租户谓词——跨租户变更 0 行命中、单键操作返回 NotFound攻击者拿着别的租户的资源 ID 来改来删得到的只是不存在。Create 强制覆盖 tenant_id。请求体里伪造tenant_id字段Create 时强制以 ViewerContext 的租户 ID 覆盖写入防伪造显式改 tenant_id 值仅放行同租户冗余设置。// 接新表 声明两行隔离自动生效func(User)Mixin()[]ent.Mixin{return[]ent.Mixin{mixin.TenantID[uint32]{},// 库层读写全形态隔离}}func(User)Policy()ent.Policy{returnTenantMutationGuardPolicy{}// 冗余层纵深防御}纵深防御在库层隔离之外还有一层仓内冗余守卫TenantMutationGuardPolicy挂着相同谓词——两层叠加任一层失效另一层兜底。现有 33 张租户表无一例外都挂了这套组合且有单测钉住守卫行为。组合策略TenantAndDataScopePolicy把租户变更防护与数据范围查询过滤链在一起——任一子策略拒绝即整体拒绝。四、行级第二维数据范围组织维度同一行隔离层里还有组织维度的过滤角色的数据范围五档——全部 / 本部门 / 本部门及以下 / 自定义 / 仅本人。由令牌 claim 承载聚合结果查询时注入created_by uid或org_unit_id IN (targets)谓词。租户隔离回答是哪个公司的数据数据范围回答是公司里谁的数据——两个正交维度叠加构成完整的行级权限模型。兜底取向同样是 fail-closed聚合出空集整体拒绝、超限退化收敛宁可不可用也不越权。五、覆盖边界诚实声明行级隔离覆盖的是ent 数据层。以下路径不会自动注入租户谓词业务侧必须自己携带并校验租户维度应用层自有缓存Redis key 构造对象存储路径OSS / MinIO 对象 key异步任务载荷asynq 任务体任何绕过 ent 的直连 SQL / GORM 路径。这是所有 ORM 级隔离方案的共同边界——接入新存储或新队列时先想清楚租户维度怎么进 key / 路径 / 载荷再写代码。风行把这条例成了接入规范而不是留给开发者踩坑。六、与套餐计费的联动隔离体系还与 SaaS 计费联动租户绑定的套餐决定可用模块白名单Api 表闸门的第三段与到期处置——READONLY 即时只读降级、BLOCK_LOGIN / FREEZE 经系统扫描任务把租户状态置为过期/冻结并吊销全部用户令牌。租户报 403 或只读先查套餐模块白名单与到期时间再查接口同步——这条排障决策树写在文档里。套餐与计费的完整机制见本系列下一篇文章。结语多租户隔离的正确姿势不是提醒每个开发者记得带租户条件而是让忘记带条件这件事不可能发生。风行把隔离编译进数据访问层、把闸门立在 HTTP 入口、把兜底做成 fail-closed三层防线加上诚实的边界声明让 SaaS 化的数据安全从代码纪律变成架构保证。项目地址https://github.com/tx7do/go-wind-admin / https://gitee.com/tx7do/go-wind-admin在线演示https://demo.admin.gowind.cloud前端/ https://api.demo.admin.gowind.cloud/docs/后端 Swagger
返回列表