一、什么是单点登录
单点登录,简称 SSO,全称 Single Sign-On。它的核心目标是:用户只需要登录一次,就可以访问多个相互信任的业务系统。
例如一个公司内部有多个系统:
- OA 系统
- 邮箱系统
- 工单系统
- 数据平台
- 权限后台
如果每个系统都要求用户单独输入账号密码,会带来很差的体验,也会增加密码泄露、弱密码复用、账号体系重复建设等问题。SSO 的价值就是把认证能力集中到一个统一的身份认证中心,由认证中心负责登录、颁发身份凭证、校验登录状态,业务系统只负责识别认证结果。
二、SSO 要解决的问题
1. 多系统重复登录
没有 SSO 时,用户访问每个系统都要登录一次。系统越多,体验越差,账号密码管理成本越高。
2. 账号体系分散
每个系统维护自己的用户表,会导致用户信息重复、权限不一致、离职账号清理困难等问题。
3. 登录安全难统一
密码策略、验证码、MFA、多端登录控制、风控策略如果分散在各个业务系统中,会很难统一升级和审计。
4. 业务系统不应直接处理密码
业务系统越多,账号密码暴露面越大。SSO 可以让业务系统不直接接触用户密码,只处理认证中心返回的身份结果。
三、SSO 的核心角色
一个典型 SSO 系统通常包括以下角色。
| 角色 | 说明 |
|---|---|
| 用户 | 浏览器或客户端的使用者 |
| 业务系统 | 用户真正要访问的应用,也叫 Service Provider、Client、Relying Party |
| 认证中心 | 统一登录系统,也叫 Identity Provider、Authorization Server |
| 账号体系 | 保存用户身份、密码、组织、角色等信息的系统 |
| 凭证 | 表示用户已认证的票据,例如 Cookie、Token、Ticket、Code |
| 回调地址 | 认证完成后跳回业务系统的地址 |
四、SSO 的基本思想
SSO 的基本思想可以概括为三句话:
- 认证中心统一完成登录。
- 业务系统不直接校验密码,只信任认证中心的结果。
- 用户登录状态通过浏览器 Cookie、授权码、Token 或 Ticket 在系统之间传递。
五、SSO 与普通登录的区别
普通登录通常只发生在一个系统内:
SSO 登录则把密码校验从业务系统抽离到认证中心:
核心差异是:普通登录由业务系统自己认证,SSO 由统一认证中心认证。
六、基于 Cookie 的同域 SSO
如果多个业务系统处于同一个主域下,例如:
app1.example.comapp2.example.comsso.example.com
认证中心可以把登录态 Cookie 写到父域 .example.com。这样子域名都能携带这个 Cookie,从而共享登录状态。
这种方式实现简单,但有明显限制:
- 只适合同一主域下的多个系统。
- Cookie 域设置过大时,可能增加泄露风险。
- 跨主域系统无法直接共享 Cookie。
- 浏览器 SameSite、第三方 Cookie 策略会影响跨站场景。
七、基于 Ticket 的 SSO
Ticket 模式常见于 CAS 一类的 SSO 协议。业务系统不直接拿用户账号密码,而是通过一次性 Ticket 向认证中心换取用户身份。
1. 登录流程
2. Ticket 的特点
- 通常是一次性的。
- 有很短的有效期。
- 绑定具体业务系统或回调地址。
- 需要由业务系统服务端向认证中心校验。
- 校验成功后,业务系统建立自己的本地会话。
3. 为什么 Ticket 要一次性
如果 Ticket 可以重复使用,一旦被日志、浏览器历史、Referer 或代理层泄露,攻击者可能拿它换取用户身份。一次性 Ticket 可以显著降低重放攻击风险。
八、基于 OAuth2 授权码模式的 SSO
OAuth2 本质上是授权协议,不是认证协议,但在实际业务中经常被用作 SSO 基础。常见流程是 Authorization Code Flow,也就是授权码模式。
1. 授权码模式流程
2. 为什么要用 Code 换 Token
授权码模式不直接把 Access Token 暴露在浏览器跳转地址中,而是先返回一个短期 Code,再由业务系统后端携带密钥去换 Token。这样可以降低 Token 泄露风险。
3. Access Token 与 Refresh Token
| Token | 作用 | 特点 |
|---|---|---|
| Access Token | 访问资源接口 | 有效期短,泄露风险较高 |
| Refresh Token | 刷新 Access Token | 有效期长,需要更严格保护 |
在纯 Web SSO 场景中,业务系统常常不会把 Access Token 直接暴露给前端,而是在服务端保存 Token,再给浏览器发业务系统自己的 Session Cookie。
九、基于 OpenID Connect 的 SSO
OpenID Connect,简称 OIDC,是建立在 OAuth2 之上的认证协议。它补充了身份认证语义,引入了 ID Token。
1. OIDC 比 OAuth2 多了什么
OAuth2 主要回答:"这个客户端是否被授权访问某些资源?"
OIDC 进一步回答:"当前登录用户是谁?"
OIDC 中常见的几个概念:
| 概念 | 说明 |
|---|---|
| ID Token | 表示用户身份的 JWT |
| Access Token | 用来访问资源接口 |
| UserInfo Endpoint | 获取用户信息的接口 |
| Scope | 授权范围,例如 openid、profile、email |
| Claims | 用户身份声明,例如用户 ID、邮箱、姓名 |
2. OIDC 登录流程
3. ID Token 校验重点
业务系统不能拿到 ID Token 就直接信任,必须校验:
- 签名是否可信。
iss是否为预期签发方。aud是否为当前业务系统客户端 ID。exp是否过期。iat是否合理。nonce是否匹配,防止重放。- 必要时校验
azp、auth_time、acr等字段。
十、SAML SSO 简介
SAML 是企业级身份联合中常见的老牌协议,尤其常见于企业 SaaS、内部系统、跨组织登录。
SAML 中常见角色:
| 角色 | 说明 |
|---|---|
| IdP | Identity Provider,身份提供方 |
| SP | Service Provider,服务提供方 |
| Assertion | 身份断言,说明用户是谁 |
| Metadata | IdP 和 SP 之间交换的配置元数据 |
SAML 的 XML 格式较重,但在企业身份联邦中仍然非常常见。
十一、前端视角下的 SSO
从前端角度看,SSO 通常表现为"跳来跳去":
- 用户打开业务页面。
- 前端或后端发现未登录。
- 页面跳转到统一登录页。
- 用户登录成功。
- 页面跳回原业务地址。
- 业务系统恢复用户访问的页面。
1. 前端通常需要处理什么
- 保存登录前的目标地址。
- 在路由守卫中判断是否需要登录。
- 处理登录回调地址上的
code、ticket、state等参数。 - 避免 Token 明文长期存储在
localStorage。 - 处理登录过期后的无感刷新或重新跳转。
- 避免无限重定向循环。
2. SPA 应用的典型流程
3. 前端不建议直接保存敏感 Token
localStorage、sessionStorage 容易受到 XSS 影响。如果业务允许,推荐后端使用 HttpOnly、Secure、SameSite Cookie 承载会话,让 JavaScript 无法直接读取敏感凭证。
十二、后端视角下的 SSO
后端是 SSO 安全闭环的关键。业务后端通常负责:
- 构造认证中心跳转 URL。
- 生成并校验
state。 - 使用 Code 或 Ticket 向认证中心换取身份。
- 校验 Token、签名、过期时间、受众、签发方。
- 创建业务系统自己的 Session。
- 管理登出、续期、权限同步。
十三、state 参数的作用
state 是 SSO 登录流程中非常重要的防护参数。它通常由业务系统生成,跳转认证中心时带上,认证中心回调时原样带回。
state 的常见用途:
- 防止 CSRF 登录攻击。
- 关联登录前后的会话。
- 保存登录完成后的跳转目标。
- 防止攻击者伪造回调。
十四、单点登出
单点登录解决"登录一次访问多个系统",单点登出则希望"退出一次,多个系统都退出"。
单点登出比单点登录更难,因为每个业务系统通常都有自己的本地 Session。认证中心登出后,业务系统的本地 Session 如果不清理,用户仍可能继续访问已登录系统。
1. 常见登出方式
| 方式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 前端 iframe 通知 | 认证中心页面嵌入多个业务系统登出地址 | 实现简单 | 受第三方 Cookie 和浏览器策略影响 |
| 后端通道通知 | 认证中心服务端调用各业务系统登出接口 | 更可靠 | 需要系统注册登出地址 |
| 短 Session | 业务系统 Session 较短,依赖自然过期 | 简单 | 不是实时登出 |
| Token 黑名单 | 登出后把 Token 加入黑名单 | 可控 | 增加存储和查询成本 |
2. 后端通知式登出流程
十五、跨域与 Cookie 问题
SSO 经常遇到跨域问题,尤其在浏览器安全策略不断收紧的环境下。
1. Cookie 的几个关键属性
| 属性 | 说明 |
|---|---|
| Domain | 控制哪些域名可以携带 Cookie |
| Path | 控制哪些路径可以携带 Cookie |
| HttpOnly | 禁止 JavaScript 读取 Cookie |
| Secure | 只允许 HTTPS 携带 Cookie |
| SameSite | 控制跨站请求是否携带 Cookie |
| Max-Age | 控制 Cookie 生命周期 |
2. SameSite 的影响
| SameSite | 行为 |
|---|---|
| Strict | 几乎不允许跨站携带 Cookie |
| Lax | 顶级导航的安全方法通常可携带 Cookie |
| None | 允许跨站携带,但必须配合 Secure |
在 SSO 跳转登录场景中,如果 Cookie 策略设置不当,可能出现认证中心明明已登录,但业务系统仍然认为未登录的问题。
十六、Token 存储方案对比
| 方案 | 优点 | 风险 |
|---|---|---|
| localStorage | 使用简单,刷新页面不丢 | XSS 后容易被读取 |
| sessionStorage | 生命周期较短 | 仍可被 XSS 读取 |
| 普通 Cookie | 自动携带 | 可被 JS 读取,需防 CSRF |
| HttpOnly Cookie | JS 无法读取 | 需要处理 CSRF 和跨域 Cookie 策略 |
| 服务端 Session | 凭证集中管理 | 服务端需要存储和扩展方案 |
一般 Web SSO 更推荐后端 Session 加 HttpOnly Cookie。前端只关心是否登录,不直接管理高敏感 Token。
十七、安全风险与防护
1. 重定向漏洞
登录完成后通常会跳回 redirect_uri 或 returnUrl。如果不校验目标地址,攻击者可以构造恶意链接,把用户登录后的跳转导向钓鱼网站。
防护建议:
- 使用白名单校验回调域名。
- 避免允许任意完整 URL。
- 内部跳转尽量使用相对路径。
- 对
redirect_uri做精确匹配。
2. CSRF 登录攻击
攻击者可能诱导用户带着攻击者账号登录目标网站,导致用户后续操作落到攻击者账号下。
防护建议:
- 使用
state参数。 - 将
state与当前浏览器会话绑定。 - 回调时严格校验。
3. Code 或 Ticket 泄露
Code、Ticket 常出现在 URL 中,可能被浏览器历史、代理日志、Referer 泄露。
防护建议:
- Code 和 Ticket 设置短有效期。
- Code 和 Ticket 只能使用一次。
- 回调完成后清理 URL 参数。
- 使用 HTTPS。
- 避免把完整 URL 写入业务日志。
4. Token 重放
攻击者拿到 Token 后重复使用,冒充用户访问系统。
防护建议:
- 缩短 Access Token 有效期。
- 使用 Refresh Token 轮换。
- 校验 Token 签名、受众、签发方、过期时间。
- 高风险操作二次验证。
- 必要时绑定设备、IP、客户端指纹。
5. XSS 窃取凭证
如果前端把 Token 存在 localStorage,一旦发生 XSS,攻击者可以直接读取 Token。
防护建议:
- 尽量使用 HttpOnly Cookie。
- 做好输入输出转义。
- 配置 CSP。
- 避免使用不可信 HTML。
- 第三方脚本最小化。
十八、SSO 与权限系统的关系
SSO 解决的是"你是谁",权限系统解决的是"你能做什么"。两者不能混为一谈。
常见做法:
- 认证中心返回用户基础身份。
- 业务系统根据用户 ID 查询本系统权限。
- 组织、角色、资源权限可以从统一权限中心同步。
- 不建议把大量业务权限全部塞进 Token,容易过期、膨胀和难以撤销。
十九、SSO 的常见实现模式
1. 中心 Session 模式
认证中心维护一个中心登录态,业务系统维护本地登录态。适合传统 Web 系统。
优点:实现直观,便于管理。
缺点:跨域和单点登出需要额外设计。
2. Token 模式
认证中心签发 Token,业务系统校验 Token。适合前后端分离、移动端、开放平台等场景。
优点:服务端状态更少,适合分布式系统。
缺点:Token 撤销、续期、安全存储更复杂。
3. 网关统一认证模式
所有请求先经过 API Gateway,由网关完成统一认证,再把用户身份透传给后端服务。
优点:业务服务接入成本低,认证逻辑集中。
缺点:网关成为关键安全边界,需要高可靠和严格防伪造。
二十、如何设计一个可靠的 SSO 系统
1. 明确系统边界
先回答几个问题:
- 有多少业务系统需要接入?
- 是否跨主域?
- 是否支持移动端、小程序、桌面端?
- 是否需要对接第三方 IdP?
- 是否要求单点登出?
- 是否需要 MFA、风控、审计?
2. 选择合适协议
| 场景 | 推荐方案 |
|---|---|
| 同主域传统 Web | Cookie 加中心 Session |
| 企业内部多系统 | CAS、OIDC 或网关统一认证 |
| 对接现代 SaaS | OIDC |
| 对接传统企业 IdP | SAML |
| 开放平台授权 | OAuth2 授权码模式 |
| 移动端登录 | OAuth2 加 PKCE 或 OIDC |
3. 建议的默认方案
对于现代 Web 系统,一个较稳妥的默认方案是:
- 使用 OIDC 授权码模式。
- 前端只负责跳转和页面状态。
- 后端处理 Code 换 Token。
- 后端校验 ID Token。
- 后端创建本系统 Session。
- 浏览器使用 HttpOnly、Secure、SameSite 合理配置的 Cookie。
- 使用
state和nonce防止 CSRF 与重放。
二十一、排查 SSO 问题的思路
SSO 问题经常表现为跳转循环、登录后仍未登录、回调失败、线上正常但本地失败等。排查时可以按链路拆分。
1. 登录跳转是否正确
检查:
client_id是否正确。redirect_uri是否和认证中心配置完全一致。scope是否包含必要权限。state是否生成并保存。- 登录前目标地址是否正确编码。
2. 回调是否正确
检查:
- 回调地址是否收到
code或ticket。 state是否与本地保存值一致。- Code 是否过期或已使用。
- 后端换 Token 请求是否成功。
- 认证中心返回的错误码含义。
3. Cookie 是否正确写入
检查:
Set-Cookie是否出现在响应头。- Cookie 的 Domain 是否匹配。
- Cookie 的 Path 是否匹配。
- HTTPS 环境下是否设置 Secure。
- 跨站场景 SameSite 是否合理。
- 浏览器是否拦截第三方 Cookie。
4. 本地 Session 是否正确建立
检查:
- Session 存储是否可用。
- 多实例部署时 Session 是否共享。
- Redis 或数据库中的 Session 是否写入成功。
- 负载均衡是否导致会话丢失。
- 用户 ID 是否正确映射到业务用户。
二十二、常见面试题
1. SSO 和 OAuth2 是一回事吗
不是。SSO 是一种登录体验和认证体系目标,OAuth2 是授权协议。OAuth2 可以作为实现 SSO 的基础,但 OAuth2 本身不直接定义"用户是谁"。如果要标准化处理身份认证,通常使用 OIDC。
2. 为什么登录后业务系统还要创建本地 Session
因为认证中心只负责证明用户身份,业务系统还需要维护自己的访问状态、权限缓存、业务用户映射和会话生命周期。本地 Session 可以减少每次请求都访问认证中心的成本。
3. 单点登出为什么难
因为登录态往往分散在多个系统中。认证中心退出不代表业务系统本地 Session 自动失效,需要通知、轮询、短会话或 Token 黑名单等机制配合。
4. Cookie SSO 为什么不能天然跨主域
浏览器 Cookie 受 Domain 限制,a.com 不能直接设置或读取 b.com 的 Cookie。跨主域通常需要通过跳转、Token、Ticket、OIDC、SAML 等协议完成身份传递。
5. 前端能不能自己拿 Code 换 Token
传统 Web 应用不建议。Code 换 Token 通常需要客户端密钥,应该在后端完成。纯前端 SPA 如果确实需要使用 OAuth2,应使用 Authorization Code Flow with PKCE,并注意 Token 存储风险。
二十三、总结
单点登录的本质,是把分散在多个系统中的认证能力集中到统一认证中心,并通过可信凭证把登录结果传递给业务系统。
理解 SSO 时可以抓住四条主线:
- 用户访问业务系统时,业务系统如何判断未登录。
- 业务系统如何把用户安全地引导到认证中心。
- 认证中心如何把认证结果安全地交还给业务系统。
- 业务系统如何建立、续期和销毁自己的本地会话。
如果是现代 Web 系统,优先考虑 OIDC 授权码模式、后端换 Token、HttpOnly Cookie、state、nonce、严格回调白名单和完整的登出策略。SSO 不只是登录跳转流程,更是一套身份、安全、会话和权限协作机制。