4、单点登录(SSO):核心原理、CAS协议与OIDC

单点登录,说白了就是「一次登录,到处通行」。你登录了公司内网,再打开OA、Jira、GitLab,系统自动就认出了你——不用反复输密码。这个体验背后,就是SSO在干活。

我刚开始接触SSO时,觉得它就是个「统一登录页」。后来在项目中踩过几次坑才明白,SSO的核心不是登录页长什么样,而是身份令牌如何在多个系统间安全传递。

SSO的核心原理

SSO要解决一个根本问题:多个互不信任的应用,如何共同信任同一个身份。

你想想看,App A和App B是两个独立的服务,各自有各自的用户库。如果让它们各自验证密码,那用户就得记两套账号。SSO的做法是引入一个「中间人」——认证中心。

认证中心负责三件事:

  • 统一认证:用户只在认证中心登录一次
  • 颁发票据:登录成功后,生成一个全局票据(Ticket)
  • 票据校验:各个应用拿着票据来找认证中心确认「这人靠谱吗?」

这里有个关键点:票据必须是一次性的、有时效的、防篡改的。我在项目中见过有人直接把用户ID明文放在Cookie里当票据用——嗯,那基本等于把家门钥匙挂在门外。

SSO的核心价值:用户只需一次认证,后续所有系统自动信任。但代价是——认证中心一旦挂了,所有系统都登不进去。

CAS协议流程

CAS(Central Authentication Service)是最经典的SSO协议之一。耶鲁大学搞出来的,后来被广泛采用。它的流程很清晰,我画了张图帮你理解:

CAS协议核心流程 用户浏览器 User Agent 业务应用 App Server CAS认证中心 SSO Server ① 访问受保护资源 ② 302重定向到CAS登录页 ③ 用户输入凭证,CAS验证通过 ④ 发放Service Ticket(ST),附带在URL中 ⑤ 应用拿着ST去CAS后台校验 ⑥ 返回用户身份信息,建立本地会话 关键点: ST是一次性票据,用完即废。CAS通过TGC(Ticket Granting Cookie)维持用户与认证中心的会话。

CAS的流程,我习惯把它拆成六个步骤:

  1. 用户访问应用:浏览器请求App的受保护资源
  2. 重定向到CAS:App发现没登录,302跳转到CAS认证中心
  3. 用户登录:用户在CAS页面输入账号密码,CAS验证通过
  4. 发放ST:CAS生成Service Ticket,通过URL参数带回App
  5. 校验ST:App拿着ST去CAS后台校验,确认票据有效
  6. 建立会话:App创建本地会话,用户访问成功

我踩过的坑:CAS的ST是一次性的。我曾经在测试环境里,因为前端重复请求了两次回调URL,导致第二次请求时ST已被消耗,用户死活登不进去。排查了半天才发现是浏览器预加载搞的鬼。

OAuth2.0与OpenID Connect的区别

很多人把OAuth2.0和OIDC搞混。我刚开始也犯过这个错——以为OAuth2.0就是做登录的。其实不是。

一句话说清楚:

  • OAuth2.0:授权协议,解决「我能访问你的什么资源」
  • OIDC:身份认证协议,解决「你是谁」

OAuth2.0的核心是Access Token,它告诉资源服务器「这个用户允许你访问他的照片」。但Access Token本身不包含用户身份信息——你拿着Token,不知道用户是谁。

OIDC在OAuth2.0之上加了一层:ID Token。这个ID Token是一个JWT,里面包含了用户的身份信息(sub、name、email等)。

对比维度 OAuth2.0 OpenID Connect
核心目标 授权(授权第三方访问资源) 认证(确认用户身份)
核心令牌 Access Token ID Token(JWT格式)+ Access Token
用户信息 Token不包含用户身份 ID Token直接包含用户身份
标准端点 /authorize, /token /authorize, /token, /userinfo
典型场景 「允许读取你的通讯录」 「使用登录知乎」

你想想看,OAuth2.0就像你给小区保安看门禁卡——保安只知道你有权限进门,但不知道你是谁。OIDC则像你出示身份证——保安不仅让你进门,还知道你的名字和年龄。

OIDC的核心流程

OIDC的流程,说白了就是OAuth2.0的Authorization Code流程,加上一个ID Token。我简单拆解一下:

  1. 客户端发起请求:用户点击「使用Google登录」,客户端构造授权请求,包含scope=openid profile email
  2. 用户授权:用户在Google登录并确认授权
  3. 返回授权码:Google重定向回客户端,附带Authorization Code
  4. 换取令牌:客户端用Code去Google的/token端点,换取Access Token和ID Token
  5. 验证ID Token:客户端验证ID Token的签名、iss、aud、exp等字段
  6. 获取用户信息:可选,用Access Token去/userinfo端点获取更多用户信息

关键区别:OAuth2.0的Access Token对客户端来说是不透明的——你没法解析它。但OIDC的ID Token是JWT,客户端可以直接解析出用户信息,不需要再调接口。

实际项目中的选择建议

我在项目中见过不少团队纠结「到底用CAS还是OIDC」。我的建议很简单:

  • 企业内部系统:CAS更成熟,部署简单,适合统一门户场景
  • 互联网应用:OIDC更灵活,支持社交登录,适合第三方集成
  • 移动端/单页应用:OIDC的PKCE流程更安全,CAS对SPA支持较弱

注意:不要自己实现SSO协议。我见过有团队自己写票据生成逻辑,结果签名算法用错了,导致任意用户都能伪造票据。直接用现成的认证服务器(Keycloak、Dex、CAS Server)比什么都强。

嗯,SSO这块内容不少,但核心就三个东西:统一认证、票据传递、令牌校验。CAS和OIDC只是实现方式不同,本质都是在解决「如何让多个系统信任同一个身份」这个问题。