4. 单点登录与联合身份

在身份安全工程师的面试中,单点登录与联合身份是高频考点。面试官往往不会只问“SAML 和 OIDC 有什么区别”,而是会追问:“用户在 A 系统登录后访问 B 系统,中间到底发生了什么?令牌怎么传?谁签的?怎么验?如果验签失败,你从哪里开始排查?”这一章我们就围绕这条主线,把四个协议讲透,并给出可落地的对比与排查思路。

一、先厘清四个协议的角色定位

很多候选人一上来就把 OAuth2.0 和 OIDC 混为一谈,这是面试中的典型失分点。必须先明确:OAuth2.0 是授权框架,不是认证协议。它解决的是“第三方应用如何在不拿到用户密码的前提下,获得访问受保护资源的授权”。而 OIDC 是构建在 OAuth2.0 之上的身份认证层,它通过引入 ID Token(一个 JWT)来回答“用户是谁”。

SAML 是更早的企业级联合身份标准,基于 XML,主要用于跨组织的 Web SSO,典型场景是企业员工用公司账号登录 Salesforce、Workday 等 SaaS。CAS(Central Authentication Service)则是耶鲁大学开源的集中式 SSO 协议,结构简单,常见于高校和内部系统,核心是“一张票据换一个身份”。

可以用一句话建立坐标系:SAML 和 CAS 是“认证协议”,OIDC 是“认证协议”,OAuth2.0 是“授权协议”。OIDC 借用了 OAuth2.0 的授权码流程,但补上了认证语义。

二、SAML 的断言与签名机制

SAML 的核心是“断言”(Assertion)。一次典型的 SP 发起 SSO 流程如下:用户访问 SP(Service Provider,如 SaaS 应用),SP 发现用户未登录,生成一个 SAML AuthnRequest,用重定向或 POST 方式把用户浏览器送到 IdP(Identity Provider,如企业 ADFS 或 Okta)。IdP 完成认证后,生成一个 SAML Response,里面包含 Assertion,Assertion 里有 Subject(用户标识)、Conditions(有效期、受众)、AttributeStatement(邮箱、部门等属性)。IdP 用自己的私钥对 Assertion 或整个 Response 签名,再通过浏览器 POST 回 SP 的 ACS 地址。SP 用 IdP 的公钥验签,检查 Audience 是否是自己、NotOnOrAfter 是否过期,通过后建立本地会话。

面试中常被追问的细节是:签名到底签在 Response 上还是 Assertion 上? 两者都允许,但 SP 必须明确校验哪一层。如果只验 Response 签名而 Assertion 未签名,攻击者可能替换 Assertion。实际排查中,如果 SP 报“签名验证失败”,第一步看 IdP 证书是否过期或轮换后未同步;第二步看 XML 规范化(Canonicalization)是否一致,因为 SAML 签名对 XML 空白和命名空间敏感。

三、OIDC 的 ID Token 与授权码流程

OIDC 最常用的流程是授权码模式。用户访问客户端应用,客户端把用户重定向到 OP(OpenID Provider)的 /authorize 端点,带上 client_id、redirect_uri、scope=openid profile email、state、nonce。用户在 OP 登录并同意后,OP 把授权码通过 redirect_uri 返回。客户端后端用授权码加 client_secret 去 /token 端点换取 access_token 和 id_token。

ID Token 是一个 JWT,结构为 header.payload.signature。Payload 中必须包含 iss(签发者)、sub(用户唯一标识)、aud(客户端 ID)、exp(过期时间)、iat(签发时间)。客户端必须验证签名(通过 OP 的 JWKS 端点获取公钥)、验证 iss 与预期一致、验证 aud 等于自己的 client_id、验证 exp 未过期,并校验 nonce 与发起时一致以防重放。

这里有一个面试高频陷阱:access_token 是给资源服务器用的,不是给客户端解析用户身份的。客户端要拿用户信息,应该解析 ID Token,或者用 access_token 去 /userinfo 端点换取。把 access_token 当身份凭证直接信任,是常见的安全设计错误。

四、CAS 的票据流转

CAS 的流程非常直观:用户访问应用(CAS Client),未登录则重定向到 CAS Server,URL 带 service 参数。CAS Server 认证后生成一个 ST(Service Ticket),重定向回应用并带上 ST。应用后端拿 ST 去 CAS Server 的 /serviceValidate 端点校验,CAS Server 返回 XML,包含用户标识和属性。应用建立本地会话。CAS 的 TGT(Ticket Granting Ticket)存在 CAS Server 侧,通过 Cookie 维持,实现“一次登录,多应用通行”。

CAS 的优点是协议简单、易于自建;缺点是属性传递能力弱于 SAML,且主要面向 Web 重定向场景,对移动端和 API 场景支持不如 OIDC 自然。

五、四协议对比与选型判断

维度 SAML 2.0 OIDC OAuth2.0 CAS
核心目的 联合认证 认证 + 轻量授权 授权 集中认证
数据格式 XML JSON / JWT JSON XML
令牌 Assertion ID Token + Access Token Access Token / Refresh Token ST / TGT
典型场景 企业 SaaS SSO 现代 Web / 移动 / API 第三方授权 高校 / 内部系统
移动端友好 较弱 强 强 弱

选型时,如果是对接企业客户、对方只支持 SAML,那就用 SAML;如果是自研新系统、需要 API 和移动端,优先 OIDC;如果只是内部几个老系统做统一登录,CAS 足够;OAuth2.0 单独出现时,永远要问一句“认证由谁负责”,不要把它当 SSO 认证协议用。

六、面试排查场景:一次 OIDC 登录失败的分析

假设客户端回调后报错 invalid_grant。排查顺序如下:第一,检查授权码是否已被使用过,OAuth2.0 授权码是一次性的;第二,检查 redirect_uri 在 /authorize 和 /token 两个请求中是否完全一致,包括末尾斜杠;第三,检查客户端时钟是否偏差过大,导致 exp 判断异常;第四,检查 client_secret 是否轮换后未更新。如果报错是 invalid_id_token,则重点看 aud 是否匹配、iss 是否与发现文档一致、JWKS 缓存的 kid 是否已更新。

这类问题的回答质量,直接体现候选人是否真正动手接过协议,而不是只背过概念。

七、可直接使用的协议选型检查清单

  • 对接方是否明确要求 SAML?若是,确认其 IdP 元数据 URL、签名算法(SHA-256 优先)、NameID 格式。
  • 若用 OIDC,确认 OP 的 discovery 文档地址,核对 issuer、jwks_uri、支持的 response_type。
  • 确认令牌有效期:ID Token 建议 5~15 分钟,access_token 按业务敏感度设定,refresh_token 需绑定客户端并支持吊销。
  • 确认是否强制 PKCE:公共客户端(SPA、移动 App)必须使用 code_challenge 与 code_verifier。
  • 确认登出行为:OIDC 的 end_session_endpoint 是否支持,SAML 的 Single Logout 是否双方都实现。
  • 确认属性映射:SAML 的 AttributeStatement 与 OIDC 的 claims 如何映射到本地用户字段,缺失时是否有兜底。

把这份清单带进面试,能让你在“协议对比”类问题中从概念层直接落到工程层,展现出身份安全工程师应有的实操判断力。