一、SSO核心准备
在讲流程前,先明确核心角色和基础约束,这是理解流程的关键:
1. 核心角色
| 角色 | 职责 | 举例 |
|---|---|---|
| 用户(User) | 访问各个业务系统,需要完成身份认证的终端使用者 | 员工、普通用户 |
| IdP(身份提供商) | 统一的身份认证中心,负责验证用户身份、颁发认证凭证(token)、管理全局会话 | 企业登录中心、微信开放平台、OAuth2.0授权服务器 |
| SP(服务提供商) | 依赖IdP完成认证的业务系统,信任IdP颁发的凭证,为用户提供具体服务 | 企业OA、CRM、报销系统、电商子站 |
2. 技术前提(保障流程安全/可行)
- 通信协议:所有交互必须基于HTTPS(防止token/账号密码被中间人窃取);
- 域名策略 :
- 同域场景:IdP和所有SP属于同一主域名(如
idp.company.com、oa.company.com、crm.company.com),Cookie可跨子域共享,流程更简单; - 跨域场景:IdP和SP域名不同(如
idp.com、sp1.com、sp2.com),需通过URL重定向、PostMessage或第三方Cookie(需浏览器允许)完成凭证传递;
- 同域场景:IdP和所有SP属于同一主域名(如
- 凭证类型 :IdP通常颁发两种token(兼顾安全和易用):
access_token(访问令牌):短期有效(1小时内),供SP验证用户身份;refresh_token(刷新令牌):长期有效(7天),用于过期后刷新access_token,通常存储在IdP的HttpOnly Cookie中。
场景1:用户首次访问某SP(如OA系统)的完整登录流程(核心)
这是SSO的基础流程,所有后续免登都依赖这次认证:
| 步骤 | 执行主体 | 具体动作(技术细节) | 核心目的 |
|---|---|---|---|
| 1 | 用户 → SP1服务器 | 用户在浏览器输入OA地址(https://oa.company.com),发起HTTP请求 |
访问目标业务系统 |
| 2 | SP1服务器 | 1. 检测到SP1本地无用户会话(无Cookie/sessionid); 2. 生成唯一state参数(防CSRF攻击); 3. 返回302重定向响应,跳转到IdP登录页:https://idp.company.com/login?redirect_uri=https://oa.company.com/callback&state=xxx |
引导用户到统一登录中心 |
| 3 | IdP服务器 | 1. 检测到IdP无全局会话(浏览器Cookie中无IdP的sessionid); 2. 返回IdP登录页面(账号密码表单) | 要求用户完成身份验证 |
| 4 | 用户 → IdP服务器 | 输入账号密码,提交登录表单(HTTPS POST请求) | 提交身份凭证 |
| 5 | IdP服务器 | 1. 验证账号密码(对比数据库/LDAP); 2. 验证通过:生成IdP全局会话(sessionid),通过Set-Cookie存入浏览器(设置HttpOnly+Secure+SameSite=Strict); 3. 生成access_token(JWT格式,含用户ID/权限,私钥签名)和refresh_token |
完成身份认证,生成全局凭证 |
| 6 | IdP服务器 | 返回302重定向响应,跳转到SP1的回调地址,并携带参数:https://oa.company.com/callback?token=xxx&state=xxx |
把token传递给SP1 |
| 7 | SP1服务器 | 1. 验证state参数(和步骤2生成的一致,防CSRF); 2. 向IdP发起验证请求:https://idp.company.com/verify_token?token=xxx; 3. 等待IdP返回验证结果 |
确认token是IdP颁发且未篡改 |
| 8 | IdP服务器 | 1. 校验token的签名(用公钥验证)、有效期、用户状态; 2. 返回验证结果(合法,附带用户基础信息) | 确认token合法性 |
| 9 | SP1服务器 | 1. 验证通过:创建SP1本地会话(生成SP1的sessionid,存入Cookie); 2. 返回OA系统页面(用户已登录状态) | 完成SP1的登录,允许访问 |
场景2:用户已登录IdP,访问其他SP(如CRM系统)的免登流程
这是SSO的核心价值------一次登录,多系统通行:
| 步骤 | 执行主体 | 具体动作(技术细节) | 核心目的 |
|---|---|---|---|
| 10 | 用户 → SP2服务器 | 输入CRM地址(https://crm.company.com),发起HTTP请求 |
访问第二个业务系统 |
| 11 | SP2服务器 | 1. 检测到SP2无本地会话; 2. 生成state参数; 3. 重定向到IdP:https://idp.company.com/login?redirect_uri=https://crm.company.com/callback&state=yyy |
引导到IdP验证是否已登录 |
| 12 | IdP服务器 | 1. 检测到浏览器Cookie中携带IdP的sessionid(全局会话有效); 2. 无需展示登录页,直接生成新的access_token(针对SP2) |
识别用户已登录,免登 |
| 13 | IdP服务器 | 重定向到SP2的回调地址,携带token=zzz&state=yyy |
传递token给SP2 |
| 14 | SP2服务器 | 验证state,并向IdP发起verify_token请求 |
验证token合法性 |
| 15 | IdP服务器 | 返回token验证结果(合法) | 确认身份 |
| 16 | SP2服务器 | 创建SP2本地会话,返回CRM系统页面(已登录状态) | 完成SP2免登,允许访问 |
场景3:全局登出流程(所有SP同步登出)
SSO不仅要"一次登录",还要"一次登出",确保所有系统同步退出:
| 步骤 | 执行主体 | 具体动作(技术细节) | 核心目的 |
|---|---|---|---|
| 17 | 用户 → SP1服务器 | 在OA系统点击"退出登录"按钮,发起登出请求 | 触发全局登出 |
| 18 | SP1服务器 | 1. 清除SP1本地会话(删除SP1的sessionid Cookie); 2. 重定向到IdP的全局登出接口:https://idp.company.com/logout?redirect_uri=https://company.com/logout_success |
通知IdP执行全局登出 |
| 19 | IdP服务器 | 1. 清除IdP全局会话(删除IdP的sessionid Cookie); 2. 遍历所有已登录的SP(IdP记录了用户登录过的SP列表),调用各SP的登出接口(如https://oa.company.com/logout、https://crm.company.com/logout) |
终止全局会话,通知所有SP登出 |
| 20 | 所有SP服务器 | 接收到IdP的登出通知,清除各自的本地会话 | 同步退出所有系统 |
| 21 | IdP服务器 | 重定向到统一的"登出成功"页面 | 完成全局登出 |
三、关键技术细节补充(避免流程漏洞)
- token的安全性保障 :
access_token必须用非对称加密(如RS256)签名:IdP用私钥签名,SP用公钥验证,防止token被篡改;access_token有效期要短(1小时内),即使被盗,攻击窗口小;refresh_token存储在IdP的HttpOnlyCookie中,禁止JS读取,防XSS攻击。
- 跨域场景的适配 :
- 若IdP和SP域名不同(如
idp.com和sp1.com),无法通过Cookie共享会话,可采用「OAuth2.0授权码模式」:IdP先返回code(授权码),SP再用code向IdP换取token,避免token暴露在URL中; - 或用「PostMessage」实现跨域通信,SP嵌入IdP的登录弹窗,登录成功后通过PostMessage传递token。
- 若IdP和SP域名不同(如
- 会话超时处理 :
- IdP的全局会话设置超时时间(如2小时无操作),超时后自动失效,用户访问新SP时需重新登录;
- SP的本地会话超时时间建议和IdP一致,避免SP会话有效但IdP会话失效的情况。
总结
- 核心逻辑:SSO的本质是「IdP统一管理身份认证,SP信任IdP颁发的token」,首次登录完成IdP全局会话创建,后续SP通过验证token实现免登;
- 关键步骤:首次登录的核心是"SP重定向→IdP认证→token回传→SP验证",免登的核心是"IdP识别全局会话→直接发token",登出的核心是"清除IdP全局会话+通知所有SP清本地会话";
- 安全关键:全程HTTPS、token短有效期+非对称签名、Cookie加HttpOnly/Secure/SameSite、state参数防CSRF。
关键点回顾:
- SSO的核心是IdP的「全局会话」和给SP颁发的「token凭证」;
- 免登的前提是IdP能识别用户的全局会话(通过Cookie中的sessionid);
- 全局登出需同步清除IdP全局会话和所有SP的本地会话。