多租户
多租户就是一套部署同时服务多家公司。每一家公司叫一个租户。所有租户共用一个 MySQL 数据库,但每家公司的数据各自隔离,互相看不到。适合用栖梧做 SaaS,把同一套后台卖给多家客户。
系统里始终有一个内置的默认租户(编码 default),它就是平台,也就是部署和运营这套系统的你自己。默认租户里的人员叫平台人员,超级管理员 admin 也在这里。
默认关闭
多租户默认关闭。关闭时就是原来的单租户系统,所有数据都属于默认租户,登录页、侧栏和日志都看不出任何变化。不需要多租户的项目可以跳过这一页。
打开开关
开关是服务端的环境变量 APP_MULTI_TENANT(写在 apps/server/.env 里,不是秘密),默认 false。界面上没有开关。它只在启动时读取,改完要重启全部服务端实例才算切换完成。
| 地方 | 关闭(默认) | 打开 |
|---|---|---|
| 可用的租户 | 只有默认租户 | 所有已启用、未到期的租户 |
| 登录页 | 没有租户编码 | 多一个“租户编码”输入框(访问的域名已绑定租户时不显示) |
| 系统管理 → 租户管理、租户套餐 | 不在侧栏里,接口也用不了(菜单管理里照常列出) | 平台人员按权限使用 |
| 日志页 | 和原来一样 | 多一列租户,见日志里的租户 |
| 系统监控 → 服务监控 | 和原来一样 | 多一行“多租户”,显示已开启 |
- 在本机试一试:把
apps/server/.env里的APP_MULTI_TENANT改为true,运行pnpm db:migrate,再重新启动pnpm dev。 - 生产环境:新安装可以一开始就打开;已有数据的库要分两次部署打开。步骤见部署 · 打开或关闭多租户。
- 上线前验收:仓库里有一份两个租户的手工验收清单,见两租户验收。
打开后不能退回旧版本
打开过开关的数据库,不能再换回 1.1.0 以前的任何版本。关闭开关前,先停用不再服务的租户,否则以后再打开时,它们会立刻恢复可用。
开关的完整说明见仓库的多租户文档 · 开关。
用户怎样登录
登录前,服务端按下面的顺序判断用户属于哪个租户:
- 看访问的域名。这个域名绑定了某个租户,就是这个租户,登录页不显示租户编码;
- 域名没有绑定租户,就看登录页填的租户编码;
- 租户编码留空,就是默认租户。平台人员登录时留空即可。

- “租户编码”在“密码登录”“短信登录”两个页签的上方。用短信登录,或者勾选了“记住用户名”时,下次会自动填上这次的编码。找回密码页也有这个输入框;
- 租户编码填错、租户已停用或已到期时,提示和密码错误完全一样(“租户编码、用户名或密码错误”),别人无法借此猜出有哪些租户;
- 登录以后,用户属于哪个租户记在服务端,没有任何请求头或参数能切换租户;
- 用户正在使用时租户被停用或到期,他的登录立即失效,登录页提示“所在租户已停用或已到期,请联系管理员”;
- 手机端(App 和微信小程序)只能用租户编码登录,见移动端 · 租户编码;
- 注册只对默认租户开放。
登录失败锁定按租户分开计算,同名的用户在不同租户里互不影响;短信的发送次数限制按手机号和 IP 计算,不分租户。见登录与账号 · 多租户时的租户编码。详细规则见仓库的租户从哪里来。
租户管理
在 系统管理 → 租户管理 中开通和管理租户。这是平台页面,只有默认租户的人员能用,权限点是 iam.tenant.*:浏览、查看、新增、修改、进入租户(enter)、重置初始密码(reset-password)。

列表里的默认租户带“默认租户”标签,它不能停用,也不能进入。
开通租户
点“新增”,填写“新增租户”表单:
| 字段 | 说明 |
|---|---|
| 租户编码 | 用户登录时填写。3–32 位小写字母、数字或中间的 -,以字母开头;default、www、api、admin 等保留字不能用。开通后不能修改,也永远不会给别的租户再用 |
| 租户名称 | 列表和横幅里显示的名称 |
| 租户套餐 | 必选,决定这个租户能用哪些功能,见租户套餐 |
| 到期时间 | 留空即永久有效 |
| 用户数上限 | 留空即不限,包括租户管理员 |
| 绑定域名 | 见绑定域名 |
| 品牌名称、品牌 logo | 见品牌 |
| 管理员用户名、显示名、手机号、邮箱 | 开通时创建的租户管理员 |
保存后一次完成以下工作,任何一步失败都会整体撤销:
- 创建租户;
- 准备这个租户的基础数据:以租户名称命名的根部门、内置角色“租户管理员”(
tenant_admin)、流程模板等; - 创建租户管理员。他拥有“租户管理员”角色,首次登录必须修改初始密码。
开通成功后弹出“租户已开通”,显示管理员用户名和初始密码。初始密码只显示这一次,点“复制”保存好,再点“我已保存”。这个租户以后新建或导入用户而不填密码时,也用这个初始密码。忘了可以在列表里点“重置初始密码”重新生成,已有用户的密码不受影响。
停用、到期和用户数
- 停用:关掉列表里的“启用状态”开关。这个租户的用户立即下线,之后无法登录,数据保留。重新启用即恢复;
- 到期:到期时间一到,效果和停用一样。续期即恢复;
- 用户数上限:新建和导入用户时检查,超出时提示“已达到租户的用户数上限”。“已用/上限”一列显示当前用了多少。
租户从不删除
租户没有删除功能。不再服务的租户,停用或让它到期就行。它的数据原样保留,用户登录不了,后台任务也不再处理它。
绑定域名
给租户绑定自己的域名后,用户在这个域名上登录不用填租户编码,别的租户的登录在这个域名上无效。平台人员仍然用主域名。
- 每个租户最多 20 个,小写,不含端口和通配符;
- 平台自己的域名不能绑定;一个域名只能绑给一个租户;
- 修改后最多 60 秒生效;
- 部署时 DNS、nginx 和 HTTPS 证书都要加上这些域名,见部署 · 打开或关闭多租户。
品牌
每个租户可以设置自己的品牌名称和品牌 logo,显示在侧栏、登录页、锁屏页和浏览器标题上。留空则使用系统的名称和图标。默认租户也可以设置品牌。
字段和修改效果的完整说明见仓库的租户管理。
租户套餐
租户套餐决定一个租户能用哪些菜单和按钮。在 系统管理 → 租户套餐 中管理,权限点是 iam.tenantPackage.*。

- 编辑套餐时,在“可用菜单”树里勾选。平台专属的菜单(见下文)不在其中;
- 用代码生成器新建的模块、在菜单管理里新建的菜单,默认不在任何套餐里。要让租户使用,就把它勾进套餐;
- 套餐由服务端检查。租户用户的权限 = 他的角色授权和套餐的交集。绕过界面直接调用不在套餐里的接口,同样会被拒绝;
- 租户管理员(
tenant_admin)自动拥有套餐里的全部功能; - 租户在 系统管理 → 角色管理 里授权时,只能看到套餐里的菜单。套餐缩小后,原来的授权保留但不生效,套餐放大后自动恢复;
- 修改套餐或给租户换套餐后,已登录的用户在下一次操作时自动更新权限,不用重新登录;
- 租户没有套餐,或者套餐被停用时,这个租户什么都不能用。正在被租户使用的套餐不能删除;
- 手机端同样按套餐隐藏功能,比如套餐里没有流程审批时,不显示“审批”页签;
- 默认租户不受套餐限制。
平台专属的页面
下面这些页面由平台统一维护,所有租户共用,不能放进套餐:
- 系统监控:服务监控、数据库监控、缓存监控、缓存列表、队列监控、定时任务、调度日志;
- 系统工具:代码生成、表单构建、系统接口、Element Plus 文档;
- 系统管理:菜单管理、字典管理、字典数据、参数设置、App 版本、客户端管理、租户管理、租户套餐;
- 系统管理 → 文件管理:存储配置;
- 系统管理 → 消息中心:邮件账号、短信渠道、站内信模板、邮件模板、短信模板;
- 系统管理 → 日志管理:API 访问日志、API 错误日志。
开关打开时,API 访问日志、API 错误日志、缓存列表和队列监控含有所有租户的数据,只有超级管理员能看。其他平台页面,默认租户里有相应权限的角色照常使用。
详细规则见仓库的租户套餐。
平台人员进入租户
租户遇到问题时,平台人员可以进入这个租户,帮忙排查或代为操作。这是跨租户操作的唯一入口。
谁能进入
- 要有“进入租户”的权限(
iam.tenant.enter),超级管理员本来就有; - 进入后,数据范围仍按本人的角色计算。所以要给他配一个数据范围为“全部数据”的角色,否则在对方租户里看不到数据,见权限与数据范围。
进入和退出
- 在租户列表里,点那一行的“进入”;
- 在弹框里填写“进入原因”(必填,最多 200 字),点“进入租户”;
- 页面整页刷新。顶部一直显示横幅“正在以平台人员身份操作租户 某某,所有操作记入审计”,旁边是“退出租户”按钮,锁屏页也会提示。

- 点横幅上的“退出租户”退出。满 2 小时、开关被关闭、或者本人的进入权限被收回时,下一次操作会自动退出;
- 只能在电脑端后台进入,手机端不行。停用、到期的租户也能进入,方便排查;
- 不是超级管理员的人,进入期间不能再进入别的租户,要先退出;
- 同时开着多个标签页时,另一个标签页进入或退出租户后,旧标签页会提示“当前标签页所在的租户已切换,请刷新页面”并自动刷新,不会把数据写到别的租户。
进入后能做什么
- 用本人的权限操作,不受对方套餐的限制;但平台功能的权限被去掉了,只有超级管理员进入期间还能打开平台页面;
- 进入的人不是对方的管理员:对方租户的所有者和租户管理员,仍然只有平台的超级管理员能修改;
- 个人资料、修改密码、表格列设置、我的站内信、公告,以及流程审批里的我的待办、我的已办、我的发起、抄送我的,进入期间仍是自己租户的。平台页面也仍在平台里运行,写入不会落到对方租户。
全程审计
- 进入和退出各记一条操作日志(动作“进入租户”“退出租户”),记在默认租户里,进入原因也一起记下;
- 进入期间的操作,记在对方租户的操作日志里。对方的管理员能看到,“操作者租户”显示“平台”,IP、地点等来源信息已遮蔽,也删不掉;
- 进入期间的每个请求,包括只是查看,都会写进 API 访问日志,完整的来源信息只在这里,只有平台的超级管理员能看。
详细规则见仓库的平台人员进入租户。
日志里的租户
开关打开后,日志页多了租户的信息:
| 页面 | 变化 |
|---|---|
| 系统管理 → 日志管理 → 操作日志 | 多一列“操作者租户”:平台人员的操作显示“平台”,否则显示租户名称 |
| 系统管理 → 日志管理 → 登录日志 | 多一列“租户”:显示“平台”、租户名称,或者“未解析租户”(登录时填的租户编码不存在)。超级管理员的搜索栏多一个“未解析租户”开关 |
| 系统管理 → 日志管理 → API 访问日志、API 错误日志 | 只有超级管理员能看,多一个租户筛选和“租户”列 |
每个租户只能看到自己的操作日志和登录日志。平台人员想看别的租户的日志,要先进入这个租户。各种日志的用法见监控与日志。
已知上限
- 一个微信号只能绑定一个租户里的一个账号。想把它释放给别的租户,见仓库的全局唯一值的释放;
- 在主域名上,同一个浏览器同一时间只能登录一个租户;
- 改绑域名最多 60 秒后生效;
- 修改任何一个套餐,所有已登录的用户都会重新加载一次权限;
- 平台人员看别的租户的日志,只能先进入这个租户;
- 品牌只有名称和 logo。浏览器标签上的小图标、网页的初始标题和 App 图标不变。
完整清单见仓库的已知上限。
在演示站体验
在线演示已经打开了多租户。登录页的租户编码填 yunshan 或 qinghe,用户名 admin,密码 KnjUB2fTabw2wnxL,就能看到一家公司登录后的样子:两家示例公司有各自的品牌名,qinghe 的套餐里没有流程审批。租户编码留空、用平台账号(admin / admin@123)登录,可以在 系统管理 → 租户管理 里点“进入”,体验进入租户和横幅。演示模式下不能开通或修改租户,进入和退出不受限制。
开发指南
- 新建的表默认按租户隔离:建表时加
tenant_id列,实体映射这一列,手写的 SQL 要自己带上租户条件。见编写租户感知的代码和仓库的编写租户感知的项目代码; - 用代码生成器生成新模块后,记得把它的菜单勾进租户套餐;
- 部署与开关的完整步骤见部署和仓库的打开多租户开关。
相关功能: