第十七章. 平台核心:多租户管理(SaaS 架构的基石)
第十七章. 平台核心:多租户管理(SaaS 架构的基石)
Prorise第十七章. 平台核心:多租户管理(SaaS 架构的基石)
摘要:本章我们将深入 RVP 5.x 架构的“灵魂”——多租户管理。我们将从 0 到 1 完整地构建一个“租户”,并深入剖析 RVP 是如何通过 “共享数据库、表级隔离”(tenant_id)这一核心模式,来实现 SaaS 平台的数据隔离、菜单隔离与权限管理。
本章学习路径
我们将从“SaaS 架构”的理论出发,完整演练“创建套餐 -> 创建租户 -> 租户登录 -> 数据隔离”的全流程:

17.1. [核心] RVP 的多租户模型:共享数据库与表级隔离
“多租户”(Multi-Tenancy)是 SaaS(Software as a Service,软件即服务)架构的核心概念。
它允许我们用 一套 软件系统,同时服务于 多个 客户(即“租户”),而每个租户都以为自己是 独占 这套系统的。
- 租户:可以是一个企业(如 A 公司、B 公司),一个组织,甚至一个个人。
17.1.1. 多租户的“独立数据库” vs “共享数据库”
实现“数据隔离”(A 公司看不到 B 公司的数据)主要有两种模式:
独立数据库模式(物理隔离):
- 原理:每个租户(A 公司)都有一个 完全独立 的数据库。
- 优点:隔离性最强,绝对安全,性能互不干扰。
- 缺点:成本极高。1000 个租户就需要 1000 个数据库实例,维护和升级将是灾难。
共享数据库模式(逻辑隔离):
- 原理:所有租户(A、B、C…)共享同一个数据库,甚至共享同一套数据表。
- 优点:成本极低,维护简单,易于扩展。
- 缺点:隔离性依赖程序设计,一旦代码出错(比如 SQL 忘了加
WHERE条件),可能导致数据泄露。
17.1.2. RVP 的选择:基于 MyBatis-Plus 的 tenant_id 隔离
RVP 5.x(作为一个追求高性价比、易于维护的框架)毫不意外地选择了 “共享数据库,表级隔离” 模式。
这是 RVP 实现数据隔离的流程:
- 在所有“需要隔离”的业务表(如
sys_user、sys_dept)上,都增加一个字段:tenant_id(租户 ID)。 A 公司(租户000001)创建的用户,tenant_id字段 全部 为000001。B 公司(租户000002)创建的用户,tenant_id字段 全部 为000002。- RVP 后端利用
MyBatis-Plus的“多租户插件”,在 系统底层“劫持”了 每一条 发出的 SQL。
当 A 公司的管理员登录后,他执行 SELECT * FROM sys_user。MyBatis-Plus 插件会自动将其 改写 为:SELECT * FROM sys_user WHERE tenant_id = '000001'
这一切对业务开发者是完全透明的! 你在写 mapper.selectList(null) 时,根本不需要关心 tenant_id,RVP 框架会自动帮你完成“数据过滤”,确保租户 A 永远(在理论上)只能看到 tenant_id = '000001' 的数据。
17.1.3. “排除表”:哪些表是“全局共享”的?
理解了 tenant_id 的自动注入,我们立刻会想到一个问题:
“难道所有表都要加 tenant_id 吗?”
当然不是。有些表是“平台级”的,是所有租户 共享 的,绝不能 被 tenant_id 隔离。
最典型的例子:
sys_menu(菜单管理):系统的“功能蓝图”只有一套。如果 A 租户能改菜单,B 租户的系统就乱套了。sys_client(客户端管理):PC 端、APP 端的 Token 策略是全局的。sys_config(参数设置):全局参数是平台维护者(超级管理员)管理的。
在 RVP 的 application.yml 配置文件中,有一个 tenant 配置项,里面明确定义了 ignore-tables(排除表),这些表将被 MyBatis-Plus 插件“放行”,不会 自动拼上 tenant_id 条件。
17.2. 租户套餐管理(sys_tenant_package):定义“卖什么”
理解了 RVP 的“SaaS 平台”本质,我们(作为平台方)要卖“产品”了。
“租户套餐”(sys_tenant_package)就是我们定义“产品规格”的地方。
- 套餐 A(基础版):每月 199 元,只提供“用户管理”、“部门管理”。
- 套餐 B(专业版):每月 999 元,提供“用户管理”、“部门管理”、“系统工具”、“代码生成”等。
我们点击 系统管理 -> 租户管理 -> 租户套餐管理 来创建这些“产品”。
17.2.1. “套餐”的本质:一个“菜单 ID 集合”
点击“新增”,我们会看到一个非常熟悉的界面:
- 套餐名称:
测试套餐(系统管理) - 关联菜单:一个“菜单权限树”。
“套餐”的本质,就是一个 menu_ids(菜单 ID 集合)的“快照”。
当我们为租户 A 分配这个“测试套餐”时,RVP 做的事情就是:
- 记录租户 A 购买了“测试套餐”。
- 租户 A 的管理员登录时,系统会告诉他:“根据你的套餐,你只能看到这些
menu_id对应的功能”。
例如,我们创建一个“测试套餐”,只勾选 系统管理 下的所有菜单。再创建“测试套餐二”,只勾选 系统工具 下的 代码生成。
17.2.2. [重点] 隔离红线:哪些“全局菜单”绝不能分配给租户?
在勾选“关联菜单”时,有一个 致命的“红线”,这是 SaaS 平台能否安全运行的 关键。
我们必须牢记:租户 只是“功能的使用者”,而 超级管理员 是“平台的维护者”。
那些“平台级”的、全局共享 的、绝不能 被 tenant_id 隔离的模块,绝对、绝对不能 分配给租户。
以下菜单是“平台级”配置,一旦分配给租户,租户 A 的修改将 立刻影响 到租户 B,导致平台崩溃:
系统管理 -> 菜单管理- 后果:租户 A 修改了菜单,租户 B 的菜单也变了,平台功能全乱。
系统管理 -> 客户端管理- 后果:租户 A 修改了 PC 端的 Token 超时,所有租户的 PC 端都受影响。
系统管理 -> 文件管理 -> 配置管理- 后果:租户 A 换了 MinIO 的 AK/SK,所有租户的文件都上传失败了。
租户管理(整个模块)- 后果:租户 A 能看到“租户 B”、“租户 C”,甚至能把他们删了。
系统监控 -> Admin 监控/任务调度中心- 后果:租户 A 能看到平台的“心脏”(服务监控、定时任务),这是最高安全风险。
[结论] 在定义“套餐”时,我们 只应该 分配那些 纯业务模块 和 已被 tenant_id 隔离 的“系统管理”功能(如 用户管理, 角色管理, 部门管理, 字典管理, 参数设置, 日志管理 等)。
17.3. 租户管理(sys_tenant):创建“新客户”
我们定义好了“产品”(套餐),现在就可以“开客户”了。
我们点击 租户管理 -> 租户管理。
我们会看到一条默认的数据 租户编号 000000,企业名称 XXX 有限公司。
这就是“平台方”,也就是“超级管理员”自己所在的“默认租户”。

这条 000000 租户的数据是 RVP 运行的基石,它是“神”,不可修改、不可禁用、不可删除。
17.3.1. [核心] 创建租户的“三要素”
我们点击“新增”,来创建我们的第一个“客户”(租户 A)。
这个表单看似复杂,但核心只有“三要素”:
- 企业信息(租户本身):
- 企业名称:
A 企业 - 联系人/电话:
Prorise/138...
- 企业名称:
- 租户套餐(购买的产品):
- 选择套餐:
测试套餐(系统管理)
- 选择套餐:
- 租户管理员(客户的第一个账号):
- 用户名:
prorise_admin - 用户密码:
admin123
- 用户名:
这个“三要素”的流程至关重要:

当我们点击“确定”时,RVP 在 一个事务 中,至少做了 三件 大事:
- 在
sys_tenant表中,插入“A 企业”的记录,生成一个新的tenant_id(例如100001)。 - 在
sys_user表中,创建一个新用户prorise_admin,并将其tenant_id设为100001。 - 在
sys_role/sys_user_role表中,为tenant_id = '100001'的环境,创建一个“管理员”角色,并将其分配给prorise_admin。 - (可能)将“超级管理员”的
sys_dict等“可隔离”的配置表,复制一份并标记tenant_id = '100001',作为 A 企业的“初始数据”。
17.3.2. 租户的“过期时间”与“绑定域名”
在新增表单中,还有两个重要的 SASS 运营配置:
- 过期时间:
- 如果不填,则“永不过期”。
- 如果设置了(例如
2025-11-12),则到期后,该租户将 无法登录 系统。这是实现“SaaS 续费”功能的基础。
- 绑定域名:
- 这是一个高级功能。
- 如果留空,所有租户都访问同一个登录页(
http://saas.com),登录时 必须手动选择 自己是“A 企业”还是“B 企业”。 - 如果为“A 企业”绑定域名
a.com。当用户访问a.com时,RVP 会自动识别域名,锁定“A 企业”,登录框 不再 显示“租户选择”,体验更佳。
17.4. 租户登录与数据隔离验证
在 17.3 节中,我们(作为超级管理员)成功创建了“A 企业”租户,并为其分配了“测试套餐”和一个管理员账号 Prorise。

现在,我们是时候“扮演”这个新租户,来亲身验证 RVP 的“隔离”是否真的生效了。
17.4.1. 登录界面的“租户选择”
我们打开一个新的浏览器(或无痕窗口),访问 RVP 的登录页。我们会发现一个在 5.x 版本中 新增 的变化:在“登录”按钮上方,出现了一个“租户选择”下拉框。
- 默认租户:
XXX 有限公司(tenant_id = 000000) - 新租户:
A 企业(tenant_id = 100001)
这个下拉框就是“SaaS 平台”的入口。我们必须先“选择”我们要登录哪家公司,然后再输入“这家公司”的账号密码。
- 选择租户:
A 企业 - 用户名:
prorise_admin - 密码:
admin123 - 点击“登录”。
17.4.2. 菜单隔离验证:租户只看到“套餐”内的菜单
登录成功!我们首先观察左侧的“菜单栏”。
- 现象:我们 只能 看到“系统管理”这一个顶级菜单。
- 对比:超级管理员能看到
系统管理、系统监控、系统工具、租户管理等所有菜单。

这就是“菜单隔离”。
原理:prorise 登录时,RVP 系统会检查:
- 他属于“A 企业”租户。
- “A 企业”租户购买的是“测试套餐”。
- “测试套餐”的“菜单 ID 集合”快照中,只包含 了
系统管理及其子菜单。 - 因此,RVP 只会给这个
prorise用户返回这些菜单的路由。
17.4.3. [核心] 数据隔离验证:租户的“用户/部门”与超管的“用户/部门”
“菜单隔离”只是第一层。真正的“SaaS 隔离”核心,是“数据隔离”。
我们点击 prorise 账号下的 系统管理 -> 用户管理。
- 现象:
- 用户列表:我们 只能 看到
prorise_admin这 一个 用户。 - 部门树:我们 只能 看到
A 企业这 一个 根节点。
- 用户列表:我们 只能 看到

我们再对比一下“超级管理员”登录时看到的“用户管理”:
- 用户列表:
admin,ry,test… 一大堆平台用户。 - 部门树:
XXX 科技,深圳总公司,长沙分公司… 庞大的组织架构。
这就是“数据隔离”。
原理:此时 prorise_admin(tenant_id = 100001)发起了 SELECT * FROM sys_user 请求。
RVP 底层的 MyBatis-Plus 插件 自动 将其改写为:SELECT * FROM sys_user WHERE tenant_id = '100001'
他自然只能看到自己租户下的数据。prorise_admin 现在可以在他 自己 的“一亩三分地”里当“皇帝”。他可以在 A 企业 这个根节点下,新增自己的 A-研发部、A-市场部;他也可以在自己的“用户管理”中,新增 A-员工1、A-员工2。
他新增的所有数据,tenant_id 都会被自动标记为 100001,永远不会 被“超级管理员”(000000)或其他租户(100002)“看到”或“污染”。
17.5. [重点] 套餐同步与权限边界
我们在 17.2 节“隔离红线”中犯了一个“错误”:我们把 菜单管理、文件配置、客户端管理 也分配给了“测试套餐”。
现在 prorise_admin 登录后,他也能看到这些“平台级”菜单,这是 极其危险 的。
我们现在必须“纠正”这个错误。
17.5.1. “同步套餐”:修改“模板”后,如何更新“实例”
- 超级管理员 登录。
- 进入 租户套餐管理,找到“测试套餐”,点击“修改”。
- 在“关联菜单”树中,取消勾选
菜单管理、客户端管理以及文件管理下的“配置管理”相关权限。 - 点击“确定”保存。
问题来了:此时,我们切换到 prorise_admin 的浏览器,刷新页面(甚至退出重登)。
- 现象:
prorise_admin依然 能看到菜单管理等危险菜单!
RVP 的“套餐”是一个“模板”。租户在创建时,只是“复制”了模板当时的“菜单 ID 快照”。
你现在修改“模板”,并 不会 自动更新所有“已售出”的“实例”(租户)。
[重点] 解决方案:“同步套餐”
我们必须(作为超级管理员)手动 去“推送”这个更新。
- 进入 租户管理 -> 租户管理。
- 找到
A 企业这一行。 - 在“操作”列中,点击
...更多,找到一个关键按钮:“同步套餐”。 - 点击它,确认“同步”。

验证:此时,我们再让 prorise_admin 退出并重新登录。
结果:菜单管理、客户端管理 等危险菜单,终于消失了。
17.5.2. 再次强调:权限的“红线”
这个“同步”的实操,再次验证了 17.2 节的“安全红线”是多么重要。
在设计 SaaS 平台的“套餐”时,必须 在第一步就规划好“哪些能给,哪些绝不能给”。
- 租户(使用者)权限:
用户管理、角色管理、部门管理、岗位管理、字典管理、参数设置、日志管理、通知公告以及 所有业务模块(如订单管理、CRM)。 - 平台(维护者)权限:
菜单管理、客户端管理、OSS配置、租户管理、监控、调度。
17.6. 超级管理员的“租户切换”
在 prorise_admin(租户 A)的浏览器中,右上角只有“个人中心”、“退出登录”等。但在“超级管理员”的浏览器中,右上角多了一个“租户切换”的下拉框。
这个功能是 RVP 多租户的“上帝模式”(God Mode)。

17.6.1. “切换租户”不是“切换用户”
我们必须搞清楚一个核心区别:当超级管理员(admin)从 XXX 有限公司 切换到 A 企业 时:
- 错误理解:我“登录成”了
prorise_admin。 - 正确理解:我(
admin)依然是admin,我的 身份(User)和 权限(Role)没有变,但我看 数据 的“视角”(tenant_id)变了。
[核心] 原理:
“租户切换”功能,仅仅是 在 admin 的 Session(或 Token)中,动态修改 了 RVP 框架所使用的 tenant_id 上下文。
- 切换前:
MyBatis-Plus插件使用tenant_id = '000000'。 - 切换后:
MyBatis-Plus插件使用tenant_id = '100001'。
17.6.2. 作为“平台客服”的运维视角
这个“上帝模式”的真正价值,在于“平台运维”。
场景:租户 A 的管理员 prorise_admin 打电话投诉:“我在我的‘用户管理’里,看不到我昨天新增的员工!”
你(超管)问他要 prorise_admin 的密码,登录他的账号去排查。
RVP 高效运维(God Mode):
- 你(超管)登录自己的
admin账号。 - 右上角“租户切换”到
A 企业。 - 打开 系统管理 -> 用户管理。
- 现象:你(
admin)的 菜单 还是“平台级”的(你依然能看到“租户管理”),但你的 数据 已经切换到了A 企业的视角。 - 你立刻在“用户列表”中看到了租户 A 的数据,发现那个“员工”被误“停用”了。
- 你(
admin)利用自己的“平台级”权限,跨越 租户 A 的权限限制,直接帮他点击了“启用”。 - 排查完毕。
- 你(
admin)切换回XXX 有限公司(默认租户),继续你的平台管理工作。
这就是“租户切换”的精髓:超级管理员(平台方)在 不丢失自己“上帝”权限 的前提下,可以 随意切换“数据视野”,去审查、管理、维护 任何一个 租户的数据。









