如何实现单点登录(SSO)
1. 概述
单点登录(Single Sign-On,简称 SSO)是一种认证机制,允许用户在多个应用系统中,只需登录一次就可以访问所有互信的系统资源。SSO 是企业级系统中常见的用户身份验证解决方案,能够提高用户体验,减少多次登录的麻烦。
2. 使用场景
- 企业内多个系统统一登录:员工在公司不同的业务系统间切换时,只需登录一次。
- 跨平台认证:如谷歌、Facebook 等第三方平台的统一身份验证。
- 提高安全性和用户体验:通过 SSO 提供的集中管理和安全机制,简化身份验证流程。
3. SSO 的主要流程
- 用户访问受保护的系统资源(应用 A)。
- 应用 A 检测用户未登录,重定向至认证服务器(SSO 服务器)。
- 用户登录 SSO 服务器:SSO 服务器验证用户的身份凭证。
- 登录成功后生成 Token:SSO 服务器创建一个全局认证 Token。
- 返回 Token 并重定向到应用 A:用户携带 Token 返回应用 A。
- 应用 A 验证 Token:应用 A 通过 Token 询问 SSO 服务器,确认该 Token 的合法性。
- 应用 A 授予用户访问权限。
- 当用户访问其他应用(应用 B)时:由于用户已在 SSO 服务器登录,SSO 服务器直接返回已验证的 Token,应用 B 授予访问权限,无需再次登录。
4. 实现 SSO 的常见方案
4.1 基于 Cookie 和 Session 的 SSO
适用于域名相同的场景下,通常在内部网络或者子域下使用。
- 同一主域的子系统共享 Cookie:SSO 服务器设置 Cookie(如
example.com
),该 Cookie 对所有*.example.com
子域都有效。 - 过程:
- 用户访问
app1.example.com
,未登录,重定向至sso.example.com
进行登录。 - 登录后,SSO 服务器设置主域 Cookie,有效范围为
.example.com
。 - 用户访问
app2.example.com
,Cookie 自动携带,应用系统无需再次验证,用户直接通过身份验证。
- 用户访问
4.2 基于 OAuth2.0 / OpenID Connect 的 SSO
适用于跨域或跨平台场景。OAuth2.0 和 OpenID Connect 是标准协议,许多第三方登录服务使用该机制。
-
OAuth2.0 流程:
- 用户访问应用 A,应用 A 重定向至 OAuth2.0 授权服务器(SSO 服务器)。
- 用户登录 SSO 服务器,授权给应用 A。
- SSO 服务器返回授权码给应用 A。
- 应用 A 使用授权码换取访问令牌(Token)。
- 应用 A 使用 Token 访问受保护的资源,并获取用户身份信息。
-
适用场景:
- 社交平台的第三方登录(如 Google、Facebook、GitHub 登录)。
- 分布式、跨平台系统中的统一认证需求。
4.3 基于 JWT(JSON Web Token)的 SSO
JWT 是一种紧凑型的身份验证标准,常用于跨域认证场景。它通过将用户信息(如用户 ID 等)编码在 Token 中,使 Token 可以跨域传递。
-
流程:
- 用户登录 SSO 服务器,成功后生成一个包含用户信息的 JWT。
- 用户访问应用 A 时,携带 JWT,应用 A 使用该 JWT 验证用户身份。
- 该 JWT 可以在多个系统间传递,使得用户只需登录一次,就可以访问多个系统。
-
优点:
- 无需依赖 Cookie,支持跨域。
- JWT 是自包含的,用户信息直接包含在 Token 中,服务端可以通过校验 JWT 验证用户身份。
4.4 基于 CAS(Central Authentication Service)的 SSO
CAS 是一个开源的 SSO 协议,提供了强大的集成能力,适用于企业级应用。
- 流程:
- 用户访问应用系统时,应用检测用户未登录,跳转至 CAS 服务器进行认证。
- CAS 服务器认证通过后,生成一个认证票据,并返回给应用系统。
- 应用系统使用该票据向 CAS 服务器验证用户身份。
- 验证成功后,应用系统为用户创建会话。
5. 详细实现步骤:基于 JWT 的 SSO 示例
5.1 用户登录并生成 JWT
在 SSO 服务器中进行身份验证,成功后生成 JWT。可以使用如 jsonwebtoken
库来生成 JWT。
const jwt = require('jsonwebtoken');
// 用户登录成功后,生成 JWT
function login(req, res) {
const user = { id: 1, username: 'user' }; // 用户信息
const token = jwt.sign(user, 'secret_key', { expiresIn: '1h' }); // 生成 Token
res.json({ token });
}
5.2 应用系统验证 JWT
在用户请求受保护资源时,应用系统从请求中获取 JWT,并进行验证。
const jwt = require('jsonwebtoken');
// 中间件验证 JWT
function verifyToken(req, res, next) {
const token = req.headers['authorization']; // 从请求头中获取 Token
if (!token) return res.status(403).send('Token is required');
jwt.verify(token, 'secret_key', (err, decoded) => {
if (err) return res.status(401).send('Invalid Token');
req.user = decoded; // 将解码后的用户信息存入请求对象
next();
});
}
5.3 前端请求
前端在登录成功后,将 JWT 保存到浏览器的 localStorage
或 sessionStorage
,并在后续请求中携带该 Token。
// 示例前端代码
fetch('/api/protected', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}` // 在请求头中添加 JWT
}
})
.then(response => response.json())
.then(data => console.log(data));
6. 常见问题
- Token 安全性:JWT 中包含用户信息,建议不要将敏感信息放入 Token 中,并使用 HTTPS 传输 Token 以避免中间人攻击。
- Token 失效处理:可以设置 Token 过期时间,并在前端或后端进行失效处理,如用户长时间未操作后需要重新登录。
- 跨域问题:如果不同系统之间存在跨域请求,需要在服务器端配置
CORS
,以允许跨域访问。
7. 总结
单点登录(SSO)提供了用户在多系统中统一登录的体验,可以使用多种方案来实现,如基于 Cookie 的 SSO、OAuth2.0、JWT 或 CAS 等。基于 JWT 的 SSO 方案适用于现代的分布式、跨域应用,具有简洁、易扩展的优势。