2026-06-13 · architecture / security
【身份与访问控制工程】IAM 全景:为什么这是高价值赛道
从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。
























一个常见的质疑是:“OIDC 已经赢了,为什么还要学 SAML?”
答案在实际的销售合同中。当你做 B2B SaaS,第一个要求”接 SSO”的企业客户——通常是 500 人以上的中大型公司——发给你的可能不是 OIDC metadata URL,而是一个 XML 格式的 Federation Metadata 文件。因为他们的 IT 部门在过去十年间围绕 Microsoft ADFS、PingFederate 或 Shibboleth 搭建了整个企业 SSO 体系,而这些东西的通用语言是 SAML 2.0。
截至 2026 年,SAML 在企业 SSO 领域的存量仍然庞大。Microsoft Entra ID(原 Azure AD)、Okta、OneLogin、PingFederate 都同时支持 SAML 和 OIDC,但大量存量企业客户使用的就是 SAML 集成。你可能不需要在新建系统时选择 SAML,但你需要能读懂它、调试它、在企业客户说”我们只支持 SAML”时接住它。
SAML 2.0(Security Assertion Markup Language,OASIS Standard, 2005)的核心思想比 OAuth/OIDC 更简单:身份提供方(IdP,Identity Provider)签发一个 XML 格式的断言(Assertion),服务提供方(SP,Service Provider)验签后信任其中的身份信息。
关键角色:
| 角色 | OIDC 对应 | 职责 |
|---|---|---|
| IdP(Identity Provider) | OP(OpenID Provider) | 认证用户,签发 SAML Assertion |
| SP(Service Provider) | RP(Relying Party) | 接收 Assertion,建立本地会话 |
| Principal(主体) | User | 被认证的用户 |
| Assertion | ID Token | 包含用户身份信息的安全声明 |
SAML 和 OIDC 在概念层是同构的——都解决”IdP 告诉 SP 用户是谁”——但协议细节天差地别。
用户访问 SP 受保护资源 → SP 将用户重定向到 IdP → IdP 认证用户 → IdP 将用户重定向回 SP,携带 SAML Response → SP 验证签名和断言,建立会话。
sequenceDiagram
participant User as 用户
participant SP as 应用 (SP)
participant IdP as 企业 IdP
User->>SP: 1. 访问受保护资源
SP->>SP: 2. 生成 SAML AuthnRequest
SP->>User: 3. 302 到 IdP SSO URL + AuthnRequest
Note over User,IdP: SAML AuthnRequest 经过浏览器
User->>IdP: 4. POST SAML AuthnRequest
IdP->>User: 5. 认证(可能已有会话,跳过)
IdP->>IdP: 6. 生成 SAML Response (含 Assertion)
IdP->>User: 7. 自动提交表单到 SP ACS URL
Note over User,SP: SAML Response 经过浏览器 POST
User->>SP: 8. POST SAML Response 到 SP ACS
SP->>SP: 9. 验证签名、断言条件、受众
SP->>User: 10. 建立本地会话, 302 到目标页面
SAML AuthnRequest 是一个经过 Base64 编码的 XML,作为 URL 参数传输。典型格式:
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_abc123"
Version="2.0"
IssueInstant="2026-06-14T10:00:00Z"
Destination="https://idp.example.com/sso"
AssertionConsumerServiceURL="https://sp.example.com/acs"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
https://sp.example.com
</saml:Issuer>
</samlp:AuthnRequest>用户已登录 IdP → 在 IdP 门户点击 SP 的图标 → IdP 生成 SAML Response → POST 到 SP ACS URL → SP 建立会话。
IdP-Initiated SSO 绕过了 AuthnRequest 的步骤——SP
是被动接收方。这意味着 SP 无法传递
RelayState(目标页面),IdP 也不会知道用户在 SP
中想去哪里。而且,IdP-Initiated SSO 缺少 AuthnRequest 的
ID 和 IssueInstant,SP
无法验证这个 Response 是对一个有效请求的响应——这是潜在的
Replay 风险。
工程陷阱 1:IdP-Initiated SSO 不在 SP-Initiated 的 CSRF 保护范围之内。如果 SP 没有额外的防重放措施(如对 Assertion ID 做去重),攻击者可以重放一个截获的 SAML Response 来登录。商用 IdP 通常给 Assertion 设置很短的 NotOnOrAfter 有效期(一般 5 分钟以内),这提供了有限的防护窗口。
一个 SAML Assertion 包含以下核心信息块:
<saml:Assertion ID="_def456" IssueInstant="2026-06-14T10:00:30Z" Version="2.0">
<saml:Issuer>https://idp.example.com</saml:Issuer>
<!-- 签名 -->
<ds:Signature>...</ds:Signature>
<!-- 条件:有效期 + 受众限制 -->
<saml:Conditions NotBefore="2026-06-14T10:00:00Z" NotOnOrAfter="2026-06-14T10:05:00Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<!-- 认证声明:IdP 怎么认证用户的 -->
<saml:AuthnStatement AuthnInstant="2026-06-14T10:00:00Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<!-- 属性声明:用户信息 -->
<saml:AttributeStatement>
<saml:Attribute Name="urn:oid:1.2.840.113549.1.9.1.1">
<saml:AttributeValue>user@company.com</saml:AttributeValue>
</saml:Attribute>
<!-- 更多属性... -->
</saml:AttributeStatement>
<!-- 主体 -->
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
user@company.com
</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
NotOnOrAfter="2026-06-14T10:05:00Z"
Recipient="https://sp.example.com/acs"
InResponseTo="_abc123"/>
</saml:SubjectConfirmation>
</saml:Subject>
</saml:Assertion>SP 的验证步骤:
<ds:Signature>)或整个 SAML
Response 的签名。NotBefore ≤ 当前时间 < NotOnOrAfter。Audience
必须等于 SP 自己的 entity ID(即
issuer)。Recipient
必须等于 ACS
URL,InResponseTo(如果存在)必须等于 SP 发出的
AuthnRequest 中的 ID。_def456),拒绝重复使用。SAML 的 NameID 是用户在 SP 中的标识符。和 OIDC 的
sub 不一样——sub 在同一个 IdP
下全局唯一,NameID 可以有不同的
Format,而且格式决定了语义:
| Format | 示例值 | 语义 |
|---|---|---|
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress |
user@company.com |
邮箱地址 |
urn:oasis:names:tc:SAML:2.0:nameid-format:persistent |
JAv2pHy8rNkMp |
不透明持久标识——同一个用户每次登录拿到的 NameID 相同,但不同 SP 间不同(pairwise pseudonymous) |
urn:oasis:names:tc:SAML:2.0:nameid-format:transient |
t+N3cVxKzLpXq |
临时标识——每次登录都不同(用于隐私场景) |
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified |
任意字符串 | 由 IdP 和 SP 协商决定 |
最麻烦的场景:两个 SP(SP-A 和
SP-B)需要关联同一个用户。如果 IdP 对两个 SP 用的都是
persistent,两边的 NameID 值会不同——无法通过
NameID 直接关联。解决办法有两种:
emailAddress:但依赖于邮箱格式的稳定性和唯一性(改名、离职后重用都会出问题)。urn:oid:0.9.2342.19200300.100.1.1(uid),让多个
SP 用同一个属性做关联。工程陷阱 2:企业客户的 IdP 管理员可以配置 NameID 的 Format 和来源。你会发现客户的 IdP 发来的 NameID 可能不是邮箱,甚至可能是一串你不认识的数字(如 AD 的
objectGUID的 Base64 编码)。确认”SP 用什么来唯一标识用户”是 SAML 集成的第一件事。
SAML Metadata 是一个 XML 文件,描述了 IdP 或 SP 的技术配置——包括 Entity ID、证书公钥、端点 URL、支持的 NameID Format、断言的签名和加密选项。它的作用类似于 OIDC 的 Discovery 文档,但 XML 比 JSON 难读得多。
企业客户的 IT 部门通常会把 IdP Metadata 的 XML 文件(或 URL)发给你,你把它导入你的 SP 配置后,SSO 集成就完成了配置侧的大部分工作。反过来,你也可能需要提供你 SP 的 Metadata 给对方——尤其是如果你的 SP 需要签名或加密时(对方需要知道你的公钥)。
Metadata 中最重要的片段:
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIE...</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://idp.example.com/sso"/>
<md:SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://idp.example.com/sso/post"/>
<md:NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
</md:NameIDFormat>
</md:IDPSSODescriptor>工程陷阱 3:Metadata 中的 X.509 证书用于验证签名,不是用于 TLS/HTTPS(那是 Web 服务器证书的事)。证书会过期——到期前 IdP 管理员会更新 Metadata。SP 必须支持 Metadata 的自动刷新或至少提供证书过期的监控和告警。证书突然过期导致所有 SAML SSO 登录失败是一个经典的 P0 事故。
| 维度 | SAML 2.0 | OIDC |
|---|---|---|
| 数据格式 | XML | JSON |
| 传输方式 | HTTP-Redirect / HTTP-POST with HTML form | HTTP Redirect + POST (JSON) |
| 移动端友好 | 差(需要浏览器重定向和表单 POST) | 好(原生 App 可直接处理) |
| 会话登出 | SAML Single Logout(复杂,兼容性差) | RP-Initiated Logout(简单,广泛支持) |
| 企业存量 | 巨大(ADFS、Shibboleth、老 Okta) | 快速增长(新系统默认选择) |
| 部署复杂度 | 高(Metadata 交换、证书管理) | 中低(Discovery URL 即开即用) |
| 何时用 | 客户已有 SAML IdP,不愿意改;需要 SAML 特定功能(如 Single Logout) | 新系统默认选择;移动端;B2C |
工程判断:对于 B2B SaaS,你需要同时支持 SAML 和 OIDC。90% 的新客户会选 OIDC,但第一个大客户来的时候很可能要 SAML。
SAML 今天不值得作为新系统的首选方案,但值得作为企业 SSO 的必接协议。核心工程要点:
上一篇:OAuth 2.1 与 PKCE:现代授权主路径 下一篇:SCIM 与账号生命周期:开通、变更、离职自动化
把当前热点继续串成多页阅读,而不是停在单篇消费。
2026-06-13 · architecture / security
从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。
2026-06-13 · architecture / security
OIDC 是当下企业 SSO 的事实标准,但大多数实现只用了它 20% 的规范。本文从 OIDC 核心规范出发,拆解 Authorization Code Flow + PKCE 的完整交互、ID Token 的验证规则、Discovery 与 Dynamic Registration 的互操作性机制,以及 RP-Initiated Logout 和 Session Management 的工程实现细节。
2026-06-20 · architecture / security
Keycloak 是 CNCF Incubating 项目中最成熟的 IAM 平台,也是自建身份系统的首选开源方案。但它不是'下个 JAR 跑起来就行'的简单软件——Realm 的隔离模型、Authentication Flow 的执行引擎、Client Scope 和 Protocol Mapper 的职责分离、自定义 SPI 扩展点——理解这些内部架构才能做好生产部署。本文从 Keycloak 的核心概念模型出发,拆解其内部执行路径和扩展机制。
2026-04-21 · architecture / security
从 OIDC、OAuth 2.1、SAML、SCIM 到多租户权限、CIAM、PAM 与身份平台选型——系统拆解现代身份与访问控制的协议、架构与工程实践。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。