4. SCIM 身份源与目标系统建模
在 SCIM 工程中,最容易出问题的往往不是协议本身,而是“谁说了算”。一个企业里通常同时存在 HR 系统、IdP(如 Okta、Azure AD、Keycloak)和大量 SaaS 应用。如果不在建模阶段明确每个系统的角色,就会出现同一用户在 HR 已离职、IdP 仍启用、SaaS 仍可登录的割裂状态。本节要解决的核心问题就是:把 HR 系统建模为权威源(Authoritative Source),把 IdP 建模为身份源与分发中枢,把 SaaS 应用建模为目标系统(Target),并在此基础上设计属性映射与转换规则。
一、三种角色的职责边界
HR 系统是权威源。它掌握员工的生命周期事实:入职、转岗、离职、组织归属、工号、成本中心。这些数据是“事实”,不应由下游系统反向修改。因此 HR 系统通常只作为 SCIM 的“上游数据提供者”,通过定时同步或事件推送把用户数据交给 IdP,而不是直接对每个 SaaS 应用发起 SCIM 请求。
IdP 是身份源与分发中枢。它从 HR 接收权威数据,补充认证相关属性(登录名、邮箱、MFA 状态),再以 SCIM 服务端(Service Provider)的身份向各 SaaS 应用下发用户与组。IdP 是 SCIM 请求的发起方(Client),SaaS 应用是接收方(Server)。
SaaS 应用是目标系统。它消费 SCIM 数据,维护本地账号,并可能回写少量状态(如 lastLogin)。目标系统不应成为属性的权威来源,否则会形成循环依赖。
二、整体数据流与建模关系
下图展示了 HR、IdP 与多个 SaaS 目标之间的数据流方向、SCIM 端点角色以及属性映射发生的位置。注意箭头方向:HR→IdP 是数据汇聚,IdP→SaaS 是 SCIM 下发,SaaS 的少量回写只用于状态观测,不参与权威判定。
三、属性映射与转换规则设计
SCIM 的核心属性集包括 userName、name.givenName、name.familyName、emails、active、externalId、groups。HR 系统的字段命名往往与 SCIM 不一致,需要在 IdP 侧建立映射表。以下是一份可直接参考的映射与转换规则示例(示例参数,非实测结果):
| HR 字段 | SCIM 属性 | 转换规则 | 目标差异处理 |
|---|---|---|---|
| emp_no | externalId | 直接映射,作为幂等键 | 目标 B 要求 externalId 唯一 |
| login_name | userName | 小写化 + 去空格 | 目标 C 不允许大写 |
| emails[type eq "work"].value | 直接映射,primary=true | 目标 A 仅接受 work 类型 | |
| status | active | 在职→true,离职→false | 离职时先 PATCH active=false |
| dept_code | groups[].display | 查部门字典转为组名 | 目标 B 用组 ID 而非名称 |
| hire_date | urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:hireDate | 格式化为 ISO 8601 | 仅目标 A 支持扩展 |
转换规则要遵循三条原则。第一,幂等键优先:externalId 应绑定 HR 的工号,确保重复同步不会创建重复账号。第二,单向权威:active、userName 等关键属性只允许从 IdP 流向 SaaS,禁止反向修改。第三,目标能力裁剪:不同 SaaS 对 SCIM 的支持程度不同,映射时要按目标能力过滤,例如目标 C 不支持 /Bulk,就应改为逐条请求。
四、同步策略与冲突处理
建模完成后,需要确定同步节奏。常见做法是:HR 每日全量 + 关键事件增量(入职、离职、转岗)触发 IdP 更新,IdP 再以 5~15 分钟为周期向 SaaS 增量同步。离职场景建议采用“先禁用、后删除”的两段式:先 PATCH active=false,保留账号用于审计,30 天后再 DELETE。
冲突处理要明确优先级:当 HR 与 IdP 数据不一致时,以 HR 为准;当 IdP 与 SaaS 不一致时,以 IdP 为准。若目标系统返回 409 Conflict,说明 externalId 或 userName 已存在,此时应查询该资源并执行 PATCH 而非 POST,避免重复创建。
五、建模检查清单
- 是否明确 HR 为唯一权威源,且下游系统无写权限?
- IdP 是否持有 SCIM Client 凭据,并按目标分别配置端点与认证方式?
- 每个目标系统是否确认了支持的 SCIM 版本、端点(/Users、/Groups、/Bulk、/Me)与 PATCH 能力?
- 属性映射表是否覆盖必填属性,并标注了转换函数与目标差异?
- 是否定义了幂等键(externalId)与冲突处理策略?
- 离职流程是否采用“禁用→延迟删除”,并保留审计窗口?