单点登录(二)

一、什么是单点登录

单点登录,简称 SSO,全称 Single Sign-On。它的核心目标是:用户只需要登录一次,就可以访问多个相互信任的业务系统。

例如一个公司内部有多个系统:

  • OA 系统
  • 邮箱系统
  • 工单系统
  • 数据平台
  • 权限后台

如果每个系统都要求用户单独输入账号密码,会带来很差的体验,也会增加密码泄露、弱密码复用、账号体系重复建设等问题。SSO 的价值就是把认证能力集中到一个统一的身份认证中心,由认证中心负责登录、颁发身份凭证、校验登录状态,业务系统只负责识别认证结果。

flowchart TD A[用户] --> B[业务系统 A] A --> C[业务系统 B] A --> D[业务系统 C] B --> E[统一认证中心] C --> E[统一认证中心] D --> E[统一认证中心] E --> F[统一账号体系]

二、SSO 要解决的问题

1. 多系统重复登录

没有 SSO 时,用户访问每个系统都要登录一次。系统越多,体验越差,账号密码管理成本越高。

2. 账号体系分散

每个系统维护自己的用户表,会导致用户信息重复、权限不一致、离职账号清理困难等问题。

3. 登录安全难统一

密码策略、验证码、MFA、多端登录控制、风控策略如果分散在各个业务系统中,会很难统一升级和审计。

4. 业务系统不应直接处理密码

业务系统越多,账号密码暴露面越大。SSO 可以让业务系统不直接接触用户密码,只处理认证中心返回的身份结果。

三、SSO 的核心角色

一个典型 SSO 系统通常包括以下角色。

角色 说明
用户 浏览器或客户端的使用者
业务系统 用户真正要访问的应用,也叫 Service Provider、Client、Relying Party
认证中心 统一登录系统,也叫 Identity Provider、Authorization Server
账号体系 保存用户身份、密码、组织、角色等信息的系统
凭证 表示用户已认证的票据,例如 Cookie、Token、Ticket、Code
回调地址 认证完成后跳回业务系统的地址
flowchart TD A[用户浏览器] --> B[业务系统] B --> C[认证中心] C --> D[账号体系] C --> E[凭证签发] E --> B[业务系统] B --> F[建立业务会话]

四、SSO 的基本思想

SSO 的基本思想可以概括为三句话:

  1. 认证中心统一完成登录。
  2. 业务系统不直接校验密码,只信任认证中心的结果。
  3. 用户登录状态通过浏览器 Cookie、授权码、Token 或 Ticket 在系统之间传递。
flowchart TD A[用户访问业务系统] --> B[业务系统发现未登录] B --> C[跳转认证中心] C --> D[用户完成登录] D --> E[认证中心生成认证结果] E --> F[跳回业务系统] F --> G[业务系统创建本地会话] G --> H[用户访问业务资源]

五、SSO 与普通登录的区别

普通登录通常只发生在一个系统内:

flowchart TD A[用户输入账号密码] --> B[业务系统校验密码] B --> C[创建本系统 Session] C --> D[返回业务 Cookie] D --> E[用户访问业务接口]

SSO 登录则把密码校验从业务系统抽离到认证中心:

flowchart TD A[用户访问业务系统] --> B[业务系统重定向到认证中心] B --> C[认证中心校验账号密码] C --> D[认证中心返回认证凭证] D --> E[业务系统校验凭证] E --> F[业务系统创建本地 Session]

核心差异是:普通登录由业务系统自己认证,SSO 由统一认证中心认证。

如果多个业务系统处于同一个主域下,例如:

  • app1.example.com
  • app2.example.com
  • sso.example.com

认证中心可以把登录态 Cookie 写到父域 .example.com。这样子域名都能携带这个 Cookie,从而共享登录状态。

flowchart TD A[用户登录 sso.example.com] --> B[认证中心写入父域 Cookie] B --> C[浏览器保存 .example.com Cookie] C --> D[访问 app1.example.com] C --> E[访问 app2.example.com] D --> F[app1 读取登录态] E --> G[app2 读取登录态]

这种方式实现简单,但有明显限制:

  • 只适合同一主域下的多个系统。
  • Cookie 域设置过大时,可能增加泄露风险。
  • 跨主域系统无法直接共享 Cookie。
  • 浏览器 SameSite、第三方 Cookie 策略会影响跨站场景。

七、基于 Ticket 的 SSO

Ticket 模式常见于 CAS 一类的 SSO 协议。业务系统不直接拿用户账号密码,而是通过一次性 Ticket 向认证中心换取用户身份。

1. 登录流程

flowchart TD A[用户访问业务系统] --> B[业务系统检查本地 Session] B --> C[未登录则跳转认证中心] C --> D[用户在认证中心登录] D --> E[认证中心生成一次性 Ticket] E --> F[重定向回业务系统并携带 Ticket] F --> G[业务系统向认证中心校验 Ticket] G --> H[认证中心返回用户身份] H --> I[业务系统创建本地 Session] I --> J[用户访问业务资源]

2. Ticket 的特点

  • 通常是一次性的。
  • 有很短的有效期。
  • 绑定具体业务系统或回调地址。
  • 需要由业务系统服务端向认证中心校验。
  • 校验成功后,业务系统建立自己的本地会话。

3. 为什么 Ticket 要一次性

如果 Ticket 可以重复使用,一旦被日志、浏览器历史、Referer 或代理层泄露,攻击者可能拿它换取用户身份。一次性 Ticket 可以显著降低重放攻击风险。

八、基于 OAuth2 授权码模式的 SSO

OAuth2 本质上是授权协议,不是认证协议,但在实际业务中经常被用作 SSO 基础。常见流程是 Authorization Code Flow,也就是授权码模式。

1. 授权码模式流程

flowchart TD A[用户访问业务系统] --> B[业务系统跳转授权服务器] B --> C[用户登录并授权] C --> D[授权服务器生成 Authorization Code] D --> E[浏览器带 Code 跳回业务系统] E --> F[业务系统后端使用 Code 换 Token] F --> G[授权服务器返回 Access Token] G --> H[业务系统使用 Token 获取用户信息] H --> I[业务系统创建本地登录态]

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 授权范围,例如 openidprofileemail
Claims 用户身份声明,例如用户 ID、邮箱、姓名

2. OIDC 登录流程

flowchart TD A[用户访问业务系统] --> B[跳转 OIDC Provider] B --> C[用户完成登录] C --> D[返回 Authorization Code] D --> E[业务后端换取 Token] E --> F[获得 ID Token 和 Access Token] F --> G[校验 ID Token 签名和声明] G --> H[创建业务系统登录态]

3. ID Token 校验重点

业务系统不能拿到 ID Token 就直接信任,必须校验:

  • 签名是否可信。
  • iss 是否为预期签发方。
  • aud 是否为当前业务系统客户端 ID。
  • exp 是否过期。
  • iat 是否合理。
  • nonce 是否匹配,防止重放。
  • 必要时校验 azpauth_timeacr 等字段。

十、SAML SSO 简介

SAML 是企业级身份联合中常见的老牌协议,尤其常见于企业 SaaS、内部系统、跨组织登录。

SAML 中常见角色:

角色 说明
IdP Identity Provider,身份提供方
SP Service Provider,服务提供方
Assertion 身份断言,说明用户是谁
Metadata IdP 和 SP 之间交换的配置元数据
flowchart TD A[用户访问 SP] --> B[SP 生成 SAML 请求] B --> C[浏览器跳转 IdP] C --> D[用户在 IdP 登录] D --> E[IdP 生成 SAML Assertion] E --> F[浏览器提交 Assertion 给 SP] F --> G[SP 校验签名和断言] G --> H[SP 创建本地会话]

SAML 的 XML 格式较重,但在企业身份联邦中仍然非常常见。

十一、前端视角下的 SSO

从前端角度看,SSO 通常表现为"跳来跳去":

  1. 用户打开业务页面。
  2. 前端或后端发现未登录。
  3. 页面跳转到统一登录页。
  4. 用户登录成功。
  5. 页面跳回原业务地址。
  6. 业务系统恢复用户访问的页面。

1. 前端通常需要处理什么

  • 保存登录前的目标地址。
  • 在路由守卫中判断是否需要登录。
  • 处理登录回调地址上的 codeticketstate 等参数。
  • 避免 Token 明文长期存储在 localStorage
  • 处理登录过期后的无感刷新或重新跳转。
  • 避免无限重定向循环。

2. SPA 应用的典型流程

flowchart TD A[用户打开 SPA 页面] --> B[前端请求当前用户接口] B --> C[接口返回未登录] C --> D[记录当前路由] D --> E[跳转认证中心] E --> F[认证中心登录成功] F --> G[跳回 SPA 回调页] G --> H[回调页处理 Code 或 Ticket] H --> I[后端创建会话] I --> J[前端跳回原始路由]

3. 前端不建议直接保存敏感 Token

localStoragesessionStorage 容易受到 XSS 影响。如果业务允许,推荐后端使用 HttpOnlySecureSameSite Cookie 承载会话,让 JavaScript 无法直接读取敏感凭证。

十二、后端视角下的 SSO

后端是 SSO 安全闭环的关键。业务后端通常负责:

  • 构造认证中心跳转 URL。
  • 生成并校验 state
  • 使用 Code 或 Ticket 向认证中心换取身份。
  • 校验 Token、签名、过期时间、受众、签发方。
  • 创建业务系统自己的 Session。
  • 管理登出、续期、权限同步。
flowchart TD A[业务后端收到回调] --> B[校验 state] B --> C[校验 Code 或 Ticket] C --> D[向认证中心换取身份] D --> E[校验用户状态] E --> F[创建本地 Session] F --> G[返回业务 Cookie]

十三、state 参数的作用

state 是 SSO 登录流程中非常重要的防护参数。它通常由业务系统生成,跳转认证中心时带上,认证中心回调时原样带回。

state 的常见用途:

  • 防止 CSRF 登录攻击。
  • 关联登录前后的会话。
  • 保存登录完成后的跳转目标。
  • 防止攻击者伪造回调。
flowchart TD A[业务系统生成随机 state] --> B[保存到服务端 Session] B --> C[跳转认证中心并携带 state] C --> D[认证中心登录后回调] D --> E[业务系统比较回调 state] E --> F[一致则继续换取身份] E --> G[不一致则拒绝请求]

十四、单点登出

单点登录解决"登录一次访问多个系统",单点登出则希望"退出一次,多个系统都退出"。

单点登出比单点登录更难,因为每个业务系统通常都有自己的本地 Session。认证中心登出后,业务系统的本地 Session 如果不清理,用户仍可能继续访问已登录系统。

1. 常见登出方式

方式 说明 优点 缺点
前端 iframe 通知 认证中心页面嵌入多个业务系统登出地址 实现简单 受第三方 Cookie 和浏览器策略影响
后端通道通知 认证中心服务端调用各业务系统登出接口 更可靠 需要系统注册登出地址
短 Session 业务系统 Session 较短,依赖自然过期 简单 不是实时登出
Token 黑名单 登出后把 Token 加入黑名单 可控 增加存储和查询成本

2. 后端通知式登出流程

flowchart TD A[用户点击退出] --> B[跳转认证中心登出] B --> C[认证中心清理中心会话] C --> D[认证中心查找已登录业务系统] D --> E[通知业务系统 A 清理 Session] D --> F[通知业务系统 B 清理 Session] D --> G[通知业务系统 C 清理 Session] E --> H[返回登出完成页] F --> H[返回登出完成页] G --> H[返回登出完成页]

SSO 经常遇到跨域问题,尤其在浏览器安全策略不断收紧的环境下。

属性 说明
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_urireturnUrl。如果不校验目标地址,攻击者可以构造恶意链接,把用户登录后的跳转导向钓鱼网站。

防护建议:

  • 使用白名单校验回调域名。
  • 避免允许任意完整 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 解决的是"你是谁",权限系统解决的是"你能做什么"。两者不能混为一谈。

flowchart TD A[用户登录] --> B[认证中心确认身份] B --> C[业务系统获得用户 ID] C --> D[业务系统查询角色和权限] D --> E[判断是否允许访问资源]

常见做法:

  • 认证中心返回用户基础身份。
  • 业务系统根据用户 ID 查询本系统权限。
  • 组织、角色、资源权限可以从统一权限中心同步。
  • 不建议把大量业务权限全部塞进 Token,容易过期、膨胀和难以撤销。

十九、SSO 的常见实现模式

1. 中心 Session 模式

认证中心维护一个中心登录态,业务系统维护本地登录态。适合传统 Web 系统。

优点:实现直观,便于管理。

缺点:跨域和单点登出需要额外设计。

2. Token 模式

认证中心签发 Token,业务系统校验 Token。适合前后端分离、移动端、开放平台等场景。

优点:服务端状态更少,适合分布式系统。

缺点:Token 撤销、续期、安全存储更复杂。

3. 网关统一认证模式

所有请求先经过 API Gateway,由网关完成统一认证,再把用户身份透传给后端服务。

优点:业务服务接入成本低,认证逻辑集中。

缺点:网关成为关键安全边界,需要高可靠和严格防伪造。

flowchart TD A[用户请求] --> B[统一网关] B --> C[校验登录态或 Token] C --> D[注入用户身份头] D --> E[业务服务] E --> F[返回业务数据]

二十、如何设计一个可靠的 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。
  • 使用 statenonce 防止 CSRF 与重放。
flowchart TD A[前端访问业务页面] --> B[后端判断未登录] B --> C[生成 state 和 nonce] C --> D[跳转 OIDC 认证中心] D --> E[用户登录] E --> F[认证中心返回 Code] F --> G[后端校验 state] G --> H[后端使用 Code 换 Token] H --> I[校验 ID Token] I --> J[创建业务 Session] J --> K[返回 HttpOnly Cookie]

二十一、排查 SSO 问题的思路

SSO 问题经常表现为跳转循环、登录后仍未登录、回调失败、线上正常但本地失败等。排查时可以按链路拆分。

1. 登录跳转是否正确

检查:

  • client_id 是否正确。
  • redirect_uri 是否和认证中心配置完全一致。
  • scope 是否包含必要权限。
  • state 是否生成并保存。
  • 登录前目标地址是否正确编码。

2. 回调是否正确

检查:

  • 回调地址是否收到 codeticket
  • state 是否与本地保存值一致。
  • Code 是否过期或已使用。
  • 后端换 Token 请求是否成功。
  • 认证中心返回的错误码含义。

检查:

  • Set-Cookie 是否出现在响应头。
  • Cookie 的 Domain 是否匹配。
  • Cookie 的 Path 是否匹配。
  • HTTPS 环境下是否设置 Secure。
  • 跨站场景 SameSite 是否合理。
  • 浏览器是否拦截第三方 Cookie。

4. 本地 Session 是否正确建立

检查:

  • Session 存储是否可用。
  • 多实例部署时 Session 是否共享。
  • Redis 或数据库中的 Session 是否写入成功。
  • 负载均衡是否导致会话丢失。
  • 用户 ID 是否正确映射到业务用户。
flowchart TD A[SSO 异常] --> B[检查跳转参数] B --> C[检查认证中心登录] C --> D[检查回调参数] D --> E[检查 Code 或 Ticket 校验] E --> F[检查 Cookie 写入] F --> G[检查业务 Session] G --> H[检查权限与用户映射]

二十二、常见面试题

1. SSO 和 OAuth2 是一回事吗

不是。SSO 是一种登录体验和认证体系目标,OAuth2 是授权协议。OAuth2 可以作为实现 SSO 的基础,但 OAuth2 本身不直接定义"用户是谁"。如果要标准化处理身份认证,通常使用 OIDC。

2. 为什么登录后业务系统还要创建本地 Session

因为认证中心只负责证明用户身份,业务系统还需要维护自己的访问状态、权限缓存、业务用户映射和会话生命周期。本地 Session 可以减少每次请求都访问认证中心的成本。

3. 单点登出为什么难

因为登录态往往分散在多个系统中。认证中心退出不代表业务系统本地 Session 自动失效,需要通知、轮询、短会话或 Token 黑名单等机制配合。

浏览器 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 时可以抓住四条主线:

  1. 用户访问业务系统时,业务系统如何判断未登录。
  2. 业务系统如何把用户安全地引导到认证中心。
  3. 认证中心如何把认证结果安全地交还给业务系统。
  4. 业务系统如何建立、续期和销毁自己的本地会话。

如果是现代 Web 系统,优先考虑 OIDC 授权码模式、后端换 Token、HttpOnly Cookie、statenonce、严格回调白名单和完整的登出策略。SSO 不只是登录跳转流程,更是一套身份、安全、会话和权限协作机制。

相关推荐
阿猫的故乡1 小时前
Vue + Axios 从入门到封装:拦截器、错误处理、请求取消、接口管理全搞定
前端·javascript·vue.js
良逍Ai出海2 小时前
免费模板搭完独立站后,我用 Codex + Figma 做了自己的页面设计
前端·人工智能·figma
纽格立科技2 小时前
DRM 发射端链路图(下)
前端·人工智能·车载系统·信息与通信·传媒
代码小库2 小时前
【2026前端转 AI 全栈指南】第 2 章(下):NestJS 项目创建 · MongoDB 配置 · 项目启动与调试
前端·数据库·mongodb
之歆2 小时前
Promise 基础技术深度解析:从回调地狱到链式调用
前端·okhttp·promise
甲维斯2 小时前
国产版“Codex”初体验,智谱ZCode很强啊!
前端·人工智能·ai编程
道友可好2 小时前
AI 怎么自己跑完一个 6 小时的任务?
前端·人工智能·后端
To_OC2 小时前
通义千问多模态生图踩坑记:我是如何把两个报错逐个干翻的
前端·aigc·vite
Bigfish_coding2 小时前
前端转agent-第一周【python】-02 FastAPI与Pydantic实战(TS/JS视角)
前端