B2B 组织属性与服务端租户边界
本文区分两种用途不同的上下文:客户端 groupId 用于记录用户当前所属的分析组织;服务端 tenantId 可用于表达由宿主认证状态确定的租户上下文。客户端传入的业务属性不能充当服务端鉴权或数据隔离依据。
1. 当前 SDK 能力
| 字段/操作 | 当前支持范围 | 边界 |
|---|---|---|
userId / identify() | Web、iOS、Android 客户端 | 由宿主提供;变更为另一用户时使用 switchUser(),不要静默覆盖身份 |
groupId | 客户端 SDK 的 group(groupId, traits);服务端 SDK 可在 ServerIdentity 显式提供 | 分析组织上下文;客户端 traits 写入 $group 事件,不作为后续事件的公共属性 |
tenantId | 协议模型及 Node.js、Java、Go、Python 服务端 SDK 的 ServerIdentity | 由服务端宿主从可信认证/业务上下文提供;当前客户端 SDK 没有设置租户 ID 的公开 API |
客户端使用 group() 记录分析组织;服务端使用 ServerIdentity.tenantId 记录可信租户上下文。租户认证与数据隔离由业务后端负责。
2. 客户端组织分析
客户端可以在宿主确认用户所属组织后调用 group()。切换组织只影响后续事件的 groupId 快照;已经创建并排队的事件保持原快照。groupTraits 随 $group 系统事件发送,不会自动附加到每条业务事件。
await analytics.identify('user-123');
await analytics.group('org-456', { plan: 'enterprise' });
analytics.track('report_exported', { format: 'csv' });org-456 和 plan 是宿主提供的分析上下文。若把组织 ID 放进普通事件属性,它仍只是普通业务数据;SDK 不会据此校验用户是否有权访问该组织。
账号切换沿用身份生命周期合同:换人时使用 switchUser();仅切换分析组织时使用 group()。退出或清理行为按 统一身份与生命周期核心概念 执行。SDK 不推断组织,也不把组织切换解释为登录或授权操作。
3. 服务端权威租户上下文
服务端 SDK 可在创建 ServerIdentity 时提供 tenantId。宿主必须从已认证的服务端请求/业务状态中取得该值,而不是信任任意客户端请求头或事件属性。示例(Java):
ServerIdentity identity = ServerIdentity.builder()
.userId(authenticatedUser.id())
.tenantId(authenticatedUser.tenantId())
.build();
client.track(TrackRequest.builder("report_exported", identity).build());Node.js、Go、Python 的服务端身份模型也接受显式 tenantId。这些 SDK 负责将宿主提供的身份快照编码到事件;认证、授权、租户归属校验和数据隔离由服务端负责。请在目标 Collector 和数据平台验证隔离策略。
订单、订阅变更、支付和退款等权威事实应由完成认证并确认业务结果的服务端产生。客户端可记录浏览、加购、点击等行为;这些行为不能证明支付或授权结果。金额字段与事件名称使用客户自己的业务合同,参考行业场景事件建模示例。
4. Web 项目与存储隔离
同源页面运行不同 SDK 项目时,应为各自配置正确的 endpoint 和 projectKey。Web SDK 按项目作用域隔离本地状态;storageNamespace 仅用于同一项目下的可选本地命名空间,不能表示租户身份,也不能代替服务端授权。不要把邮箱、手机号或 Token 放入命名空间。
5. 验收范围
| 验证项 | 本地可验证 | 需要对应部署系统验证 |
|---|---|---|
group() 更新后续事件上下文,旧事件快照不变 | 客户端单测/Host 测试 | — |
服务端 ServerIdentity.tenantId 序列化到事件 | 四语言服务端 SDK 测试 | Collector 是否据此隔离数据 |
tenantId 来源可信 | — | 服务端认证、授权和租户归属检查 |
| Kafka/数据库/分析仓库中的租户隔离 | — | 对应数据平台部署与权限测试 |
| Web 不同项目的本地状态隔离 | 浏览器多项目测试 | 实际生产项目凭据与环境配置 |
租户隔离需要在目标 Collector、数据库及数仓中分别验证。