2. SCIM 核心资源模型
SCIM 的价值不在于“能传 JSON”,而在于它用一套可扩展、可校验、可互操作的资源模型,把不同身份源里的账号、组和人员属性映射到统一语义上。理解 SCIM 的第一步,是分清三个核心资源:User 表示一个可登录的主体,Group 表示成员集合,EnterpriseUser 则是对 User 的企业级扩展,用来承载员工编号、部门、经理、成本中心等组织属性。三者不是并列孤岛,而是“基础资源 + 扩展资源”的组合关系。
User:最小可登录主体
User 资源的核心字段包括 id、externalId、userName、name、emails、active、groups 和 meta。其中 userName 是登录标识,通常要求唯一;name 是复合属性,包含 givenName、familyName、formatted 等子属性;emails 是多值属性,每个值可带 type、primary 标记。下面是一个典型的 User 资源片段:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "2819c223-7f76-453a-919d-413861904646",
"externalId": "emp-10086",
"userName": "zhangsan@example.com",
"name": {
"givenName": "三",
"familyName": "张",
"formatted": "张三"
},
"emails": [
{ "value": "zhangsan@example.com", "type": "work", "primary": true },
{ "value": "zs@personal.example", "type": "home" }
],
"active": true,
"meta": {
"resourceType": "User",
"created": "2024-03-01T08:00:00Z",
"lastModified": "2024-06-12T10:30:00Z",
"version": "W/\"a1b2c3\""
}
}
这里要特别注意 schemas 字段:它声明了该资源遵循哪些 schema。核心 User 的 schema URN 是 urn:ietf:params:scim:schemas:core:2.0:User。如果资源还带有企业扩展,就必须同时声明扩展 schema 的 URN。
Group:成员关系与多值引用
Group 资源相对简单,核心字段是 displayName 和 members。members 是多值属性,每个成员通过 value 引用 User 的 id,并可用 type 区分是 User 还是 Group,用 display 提供可读名称。Group 的成员关系是 SCIM 同步中最容易出问题的部分:成员是“引用”而不是“内嵌对象”,因此删除、重命名、跨域引用都需要谨慎处理。
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "e9e30dba-f08f-4109-8486-d5c6a331660a",
"displayName": "研发中心",
"members": [
{ "value": "2819c223-7f76-453a-919d-413861904646",
"type": "User", "display": "张三" },
{ "value": "8f2b1c44-0a11-4d5e-9c77-2b6a1f0d3e21",
"type": "User", "display": "李四" }
]
}
EnterpriseUser:用扩展承载组织属性
EnterpriseUser 不是独立资源,而是 User 的扩展 schema,URN 为 urn:ietf:params:scim:schemas:extension:enterprise:2.0:User。它把 employeeNumber、department、manager、costCenter、organization 等属性集中在一个命名空间下。在 JSON 中,扩展属性通常放在以 URN 为键的对象里:
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"userName": "zhangsan@example.com",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "10086",
"department": "平台研发部",
"manager": {
"value": "8f2b1c44-0a11-4d5e-9c77-2b6a1f0d3e21",
"displayName": "李四"
}
}
}
扩展机制的关键在于:schema 是命名空间,不是字段前缀。任何自定义属性都应注册到自定义 schema URN 下,而不是随意往核心 User 里塞字段。这样不同厂商、不同租户的扩展才能共存而不冲突。
属性类型与多值属性
SCIM 定义了 string、boolean、decimal、integer、dateTime、binary、reference 和 complex 等类型。其中 complex 类型用于复合结构,如 name、manager、emails 中的每一项。多值属性则用数组表达,每个元素可带 type、primary、display 等子属性。多值属性的更新语义是“整体替换”还是“按值合并”,取决于服务端实现,工程上必须通过 PATCH 的 path 明确指定,例如 path: "emails[type eq \"work\"].value"。
资源 ID 与外部 ID 的设计
id 是 SCIM 服务端生成的全局唯一标识,客户端不应自行指定;externalId 则是客户端侧的业务主键,用于把 SCIM 资源与 HR、AD、数据库中的记录关联起来。设计上应遵循:id 只用于 SCIM 内部引用,externalId 用于跨系统对账;externalId 应稳定、唯一、不随展示名变化;meta.version 用于乐观锁,避免并发覆盖。
工程落地中的关键判断
在实际对接中,最容易踩坑的是三件事。第一,把 externalId 当 id 用:一旦 HR 系统改了工号,SCIM 侧就会产生重复账号。正确做法是 externalId 只用于匹配,id 始终由 SCIM 服务端维护。第二,多值属性直接整体覆盖:如果 PATCH 时把 emails 整个数组替换,可能把用户自己添加的备用邮箱删掉。应使用带过滤条件的 path 精确更新。第三,扩展属性未声明 schemas:服务端可能直接丢弃未知字段,导致部门、经理信息同步失败。每次写入扩展属性时,都要确认 schemas 数组包含对应 URN。
schemas;多值属性是否支持按 type 过滤更新;meta.version 是否在 PUT/PATCH 时参与并发校验。把 User、Group、EnterpriseUser 三者的关系理清,再理解 schema 扩展与多值属性的更新语义,后续的同步策略、冲突处理和审计对账才有稳定的模型基础。