SSO 单点登录
前言
在数字化时代,用户访问多个应用程序和服务已成为常态。无论是企业内部的办公系统,还是面向公众的在线服务,用户往往需要在不同的平台上进行身份验证。然而,频繁的登录操作不仅繁琐,还可能降低用户体验,甚至成为安全漏洞的温床。为了解决这一问题,单点登录(Single Sign-On,简称SSO)应运而生。
什么是单点登录?
单点登录(Single Sign-On,简称SSO)是一种身份验证机制,允许用户使用一组凭据(通常是用户名和密码)登录到一个系统后,无需再次输入凭据即可访问其他相关系统。SSO的主要目的是简化用户的登录过程,提高用户体验,并减少用户在多个系统中管理多个账户的负担。
单点登录的工作原理
- 身份验证中心(Identity Provider, IdP) :SSO系统通常有一个中央身份验证中心,用户在这个中心进行一次登录。
- 服务提供者(Service Provider, SP) :用户需要访问的其他系统(子系统)被称为服务提供者。这些系统信任身份验证中心,并允许用户在通过身份验证后访问它们。
- 令牌(Token) :用户在身份验证中心登录后,会获得一个令牌(通常是一个加密的会话标识符)。这个令牌会被传递给服务提供者,服务提供者通过验证这个令牌来确认用户的身份。
单点登录的优点
- 简化用户登录过程:用户只需登录一次,即可访问多个相关的子系统,无需重复输入凭据。
- 提高用户体验:减少用户在多个系统中管理多个账户的负担。
- 增强安全性:通过集中管理用户身份和权限,减少安全漏洞。
- 降低管理成本:集中管理用户身份和权限,减少重复工作。
单点登录的缺点
- 实现复杂:不同的SSO实现方式有不同的复杂性,需要根据具体需求选择合适的方式。
- 安全性依赖:SSO系统的安全性依赖于身份验证中心的安全性,一旦身份验证中心被攻破,所有信任该中- 心的系统都可能受到影响。
- 跨域问题:跨域的SSO实现需要特殊处理,增加了实现的复杂性。
单点登录的实现方式
实现方式 | 适用场景 | 实现步骤 | 优点 | 缺点 |
---|---|---|---|---|
基于Cookie的SSO | 适用于Web应用,尤其是同域或跨域的子系统。 | 1. 创建一个中央身份验证中心(IdP),用户在这里进行登录。2. IdP登录成功后,设置一个包含用户身份信息的Cookie。3. 子系统信任IdP设置的Cookie,并使用它来验证用户身份。 | 1. 实现简单,适用于同域或跨域的Web应用。2. 用户登录后,无需再次输入凭据。 | 1. 跨域问题需要特殊处理(如使用CORS或服务器端代理)。2. 安全性依赖于Cookie的安全性。 |
基于OAuth 2.0/OpenID Connect的SSO | 适用于Web应用、移动应用和API服务。 | 1. 使用OAuth 2.0或OpenID Connect协议作为身份验证中心(IdP)。2. 用户在IdP登录后,IdP会颁发一个访问令牌(AccessToken)和一个身份令牌(ID Token)。3. 子系统使用这些令牌来验证用户身份。 | 1. 支持多种客户端类型(Web、移动、API)。2. 安全性高,令牌可以加密和签名。 | 1. 实现相对复杂,需要理解OAuth 2.0/OpenID Connect协议。2. 需要处理令牌的颁发、验证和刷新。 |
基于SAML的SSO | 适用于企业内部应用和B2B场景。 | 1. 使用SAML协议作为身份验证中心(IdP)。2. 用户在IdP登录后,IdP会生成一个SAML断言(Assertion),包含用户身份信息。3. 子系统使用SAML断言来验证用户身份。 | 1. 广泛应用于企业内部和B2B场景。2. 支持多种身份验证方式(如LDAP、AD)。 | 1. 实现复杂,需要理解SAML协议。2. 配置和调试相对困难。 |
基于JWT(JSON Web Token)的SSO | 适用于Web应用、移动应用和API服务。 | 1. 用户在身份验证中心(IdP)登录后,IdP会生成一个JWT。2. JWT包含用户身份信息,并使用密钥签名。3. 子系统使用相同的密钥验证JWT的签名,并提取用户身份信息。 | 1. 轻量级,易于实现和使用。2. 支持跨域和跨平台。 | 1. 安全性依赖于密钥的管理。2. 令牌一旦颁发,无法撤销(除非设置过期时间)。 |
基于CAS(Central Authentication Service)的SSO | 适用于企业内部应用和教育机构。 | 1. 部署一个CAS服务器作为身份验证中心。2. 子系统集成CAS客户端,信任CAS服务器的身份验证结果。3. 用户在CAS服务器登录后,CAS服务器会生成一个票据(Ticket),子系统使用这个票据来验证用户身份。 | 1. 开源,社区支持广泛。2. 支持多种身份验证方式(如LDAP、AD)。 | 1. 配置和部署相对复杂。2. 需要维护CAS服务器。 |
以上就是在网上搜集资料后总结出来的几种实现方案,不过在企业中的比较多的是如下三种方式。
Session+Cookie、Token和双Token方式实现单点登录
实现方式 | Session+Cookie | Token | 双Token |
---|---|---|---|
原理 | 1. 用户登录后,服务器生成一个Session ID。2. Session ID存储在服务器端,用户信息存储在Session中。3. Session ID通过Cookie传递给客户端。4. 客户端每次请求时,携带Cookie中的Session ID。5. 服务器根据Session ID查找对应的Session,验证用户身份。 | 1. 用户登录后,服务器生成一个Token(通常是JWT)。2. Token包含用户信息,并使用密钥签名。3. Token通过响应返回给客户端。4. 客户端每次请求时,携带Token。5. 服务器验证Token的签名,提取用户信息。 | 1. 用户登录后,服务器生成两个Token:访问令牌(Access Token)和刷新令牌(Refresh Token)。2. Access Token用于短期访问,Refresh Token用于获取新的Access Token。3. Access Token通过响应返回给客户端,Refresh Token通常存储在安全的地方(如HttpOnly Cookie)。4. 客户端每次请求时,携带Access Token。5. 服务器验证Access Token,如果过期,客户端使用Refresh Token获取新的Access Token。 |
优点 | 1. 实现简单,适用于同域应用。2. 服务器端存储用户信息,安全性较高。3. 支持会话管理,可以随时撤销会话。 | 1. 无状态,服务器无需存储用户信息,扩展性好。2. 支持跨域和跨平台。3. 轻量级,易于实现和使用。 | 1. 安全性高,Refresh Token存储在安全的地方,不易被窃取。2. 支持Token刷新,减少用户频繁登录。3. 适用于需要长期会话的场景。 |
缺点 | 1. 服务器需要存储Session,扩展性差。2. 跨域问题需要特殊处理。3. 安全性依赖于Cookie的安全性。 | 1. Token一旦颁发,无法撤销(除非设置过期时间)。2. 安全性依赖于密钥的管理。3. Token可能较大,影响性能。 | 1. 实现相对复杂,需要处理Token的颁发、验证和刷新。2. 需要额外的存储和处理Refresh Token。 |
适用场景 | 1. 同域Web应用。2. 需要会话管理的场景。3. 安全性要求较高的场景。 | 1. 跨域和跨平台应用。2. 无状态应用。3. 轻量级应用。 | 1. 需要长期会话的场景。2. 安全性要求高的场景。3. 需要Token刷新的场景。 |
安全性 | 1. 安全性较高,服务器端存储用户信息。2. 支持会话管理,可以随时撤销会话。 | 1. 安全性依赖于密钥的管理。2. Token一旦颁发,无法撤销(除非设置过期时间)。 | 1. 安全性高,Refresh Token存储在安全的地方,不易被窃取。2. 支持Token刷新,减少用户频繁登录。 |
扩展性 | 1. 扩展性差,服务器需要存储Session。2. 适用于同域应用。 | 1. 无状态,扩展性好。2. 支持跨域和跨平台。 | 1. 扩展性较好,但需要处理Token的颁发、验证和刷新。2. 适用于需要长期会话的场景。 |
总结
- Session+Cookie:适用于同域Web应用,安全性较高,但扩展性差。服务器压力也比较大,因为服务器需要存储Session
- Token:适用于跨域和跨平台应用,无状态,扩展性好,但安全性依赖于密钥管理。
- 双Token:适用于需要长期会话和安全性要求高的场景,支持Token刷新,但实现相对复杂。
选择哪种方式实现单点登录取决于具体需求和技术栈。每种方式都有其优缺点,需要根据实际情况进行选择和配置。
实现过程
单点登录(Single Sign-On, SSO)的实现过程通常涉及一个中央认证中心(Identity Provider, IdP)和多个子系统(Service Provider, SP)。以下是单点登录的实现过程描述:
用户在子系统A登录
用户访问子系统A:用户尝试访问子系统A,但尚未登录。
重定向到认证中心:子系统A检测到用户未登录,将用户重定向到中央认证中心(IdP)进行身份验证。
用户登录:用户在认证中心输入用户名和密码进行登录。
颁发令牌:认证中心验证用户身份后,颁发一个令牌(如JWT),并将用户重定向回子系统A。
存储令牌:子系统A接收到令牌后,通常将其存储在客户端(如Cookie、localStorage或者 sessionStorage)中。
用户访问子系统B
- 用户访问子系统B:用户尝试访问子系统B,但尚未登录。
- 重定向到认证中心:子系统B检测到用户未登录,将用户重定向到中央认证中心(IdP)进行身份验证。
- 认证中心验证令牌:认证中心检查用户是否已经登录(通过检查存储在Cookie、localStorage或者 sessionStorage中的令牌)。
- 重定向回子系统B:如果用户已经登录,认证中心将用户重定向回子系统B,并附带令牌。
- 存储令牌:子系统B接收到令牌后,通常将其存储在客户端(如Cookie、localStorage或者 sessionStorage)中。
中间跳转页面
在单点登录过程中,通常会有一个中间跳转页面(也称为“跳板页面”或“中间件页面”),用于处理重定向和令牌传递。这个页面通常由认证中心提供,用于确保用户在不同子系统之间的无缝切换。
子系统B如何知道用户已登录
- 令牌验证:子系统B接收到令牌后,会验证令牌的有效性(如签名、过期时间等)。
- 用户信息提取:如果令牌有效,子系统B会从令牌中提取用户信息,并允许用户访问受保护的资源。
- 无需再次登录:由于用户已经在认证中心登录并获得了有效的令牌,子系统B不会跳转到登录页面,而是直接允许用户访问。
中间跳转页面的作用
- 重定向:中间跳转页面负责将用户从子系统A重定向到认证中心,并在用户登录后将用户重定向回子系统A。
- 令牌传递:中间跳转页面负责在用户登录后将令牌传递给子系统A,并在用户访问子系统B时将令牌传递给子系统B。
- 无缝切换:中间跳转页面确保用户在不同子系统之间的切换是无缝的,用户无需再次输入凭据。
示例代码
以下是一个简单的中间跳转页面的示例代码,展示如何将令牌存储在 sessionStorage 中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSO Redirect</title>
</head>
<body>
<script>
// 获取URL参数
function getUrlParam(name) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(name);
}
// 获取令牌
const token = getUrlParam('token');
const targetUrl = getUrlParam('target');
if (token && targetUrl) {
// 将令牌存储在sessionStorage中
sessionStorage.setItem('access_token', token);
// 重定向到目标URL
window.location.href = targetUrl;
} else {
// 如果没有令牌或目标URL,重定向到登录页面
window.location.href = '/login';
}
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
总结
单点登录的实现过程涉及以下关键步骤:
- 用户在子系统A登录:用户在认证中心登录,并获得令牌。
- 用户访问子系统B:子系统B通过认证中心验证令牌,并允许用户访问。
- 中间跳转页面:负责处理重定向和令牌传递,确保用户在不同子系统之间的无缝切换。
通过这种方式,用户在子系统A登录后,访问子系统B时无需再次登录,认证中心负责验证用户身份并颁发令牌,不同的子系统信任认证中心颁发的令牌,从而实现单点登录。