在 Talentera(Bayt.com 的 B2B 招聘平台),我花了几年为企业和政府设计多租户工作流,使用同一套代码库。数据模型在第一天看起来不错,更令人意外的是——它在多年的租户专属需求下存活了下来。诀窍是把身份+访问控制当作一等设计维度,而不是在业务逻辑写完之后才螺栓上去的中间件关切。这篇文章是我会向任何在2026年建设多租户平台的工程师推荐的东西的简短版本。
问题的形状
多租户招聘对访问控制来说几乎是最坏的情况:
- 多个租户类别。 企业、小型企业、政府部委——同一个平台,对”隔离”意味着什么的预期截然不同。
- 共享员工。 这个季度为一个机构工作、下个季度为另一个机构工作的招聘人员。他们的历史不能泄漏。他们的凭证应该是可携带的。
- 候选人是跨租户的原语。 一个候选人向十家公司的职位申请。这些公司不应该看到彼此对那个候选人的互动。
- 政府合同带来审计要求。 不是”我们记录东西”。是正式的要求,有定期审计,有漏掉的法律后果。
这些要点里的每一个首先都是身份/访问控制问题。平台的其余部分是在上面的一层薄薄的东西。
有效的模型
交付并存活下来的模型是围绕四个原语建立的:
1. 租户作为不可为空的一等实体
数据库里的每一行都有一个租户列,由数据库级约束强制执行。不是应用层过滤器。不是”我们会记得加上它”。Postgres 的行级安全策略(或其他存储的等效机制)。如果一个工程师写了一个不包含租户过滤器的查询,数据库会报错。
权衡是每个查询看起来都稍微冗长一些。收益是应用程序里的 bug 永远无法导致跨租户泄露,因为数据库拒绝服务那个请求。
2. 主体/关系/资源,而不是用户/角色
现成的模型——用户有角色,角色有权限,权限保护资源——对简单应用来说还行。在多租户招聘环境里它会崩溃,因为用户的角色取决于他们在哪个租户里运作。在机构 A 是”管理员”的招聘人员,在机构 B 是”访客”,在机构 C 是”没有”。
我们使用的模型更接近 Zanzibar 风格(在 Zanzibar 成为工程社区的家常词汇之前):主体对一个资源有一种关系,由当前租户上下文调解。一个查询回答”在这个上下文中,这个主体能对这个资源做这个操作吗?“而答案从关系图计算出来,不是从角色枚举。
这一个改变解锁了几十个在角色枚举模型里需要定制权限代码的产品功能。
3. 共享身份,作用域化的 session
用户有一个身份——他们的登录。当他们认证时,他们得到一个限定到特定租户的 session token。切换租户意味着签发一个新 session,不是改变现有的。session 携带租户 ID、主体在那个租户里的相关关系,以及 session 自己的审计可见标识符。
这意味着每一个被审计的操作都可以轻松追溯到(主体、租户、session、时间戳)——而来自审计人员的”谁为谁做了什么”的问题变成了一个单一查询的答案。
4. 审计作为只追加的领域事件
系统里的每一次变更都向一个只追加的审计日志发出一个领域事件。审计日志是应用程序 schema 的一等公民,不是一个运维事后想法。当一个政府审计人员问”给我看这个招聘人员三月份所有的简历查看记录”时,答案是一个查询,不是一个多周的日志关联练习。
从第一天就建这个是事后补的3倍便宜。我知道,因为我两者都做过。
失败的地方
我搞错的两件事:
1. 第一版角色继承太平坦了。 我们有一个管理员-用户-贡献者层级,就这些了。企业想要子管理员。我们不得不事后添加角色组合,这意味着解开一堆”管理员意味着所有这些”的假设。正确的做法是从第一天就建立组合——但直到第20个客户我才看到需求。
2. 多租户模型没有干净地扩展到分析。 对于事务查询,行级租户范围是无懈可击的。对于 BI/报表工作负载,它很快变得昂贵。我们最终建了一个在流水线级别而不是查询级别强制执行租户边界的独立分析流水线。那有效——但是建了两次的水管工作量相当大,如果重来我会做不同的事。
2026年我会做什么不同的事
四年后,从头开始,我会:
- 从第一天就用 OPA(Open Policy Agent) 或类似的策略引擎,而不是自己建权限评估引擎。更便宜、经过审计、测试充分,概念模型是相同的。
- 使用 Postgres 行级安全或等效的硬边界。不是”我们会在应用层过滤”。边界必须在数据库层。
- 在写第一个变更 endpoint 之前选好结构化审计事件 schema。每个事件是(行为者、主体、操作、资源、租户、时间戳、结果、差异)。如果一个新功能需要一个 schema 不支持的事件形状,那是一次 schema 对话,不是”随便记录点什么”。
- 使用 OpenID Connect + 专用身份提供商,而不是自己滚 auth。Pocket ID、Keycloak、Auth0、Ory——好的选项比 DIY 成本更便宜。
可以推广的模式
这些都不是招聘专属的。每个 B2B SaaS、每个多租户平台、每个政府相关系统都有相同的形状。大多数它们都一团糟的原因是身份和访问控制被当作中间件——螺栓上去的、规格不足的、从不优先考虑的。那些经久耐用的把身份当作产品维度:领域模型的一部分、设计评审的一部分、路线图的一部分。
如果你现在在建一个多租户平台:身份模型是你第一年要做出的最承重的设计选择。 你无法便宜地补。把它做对。花这个时间。读 Zanzibar 论文。和做过的人交流。它复利。