SSO单点登录
1. 由来
SSO(Single Sign-On)是一种身份验证和授权机制,它允许用户只需一次登录就可以访问多个应用系统。SSO的出现主要是为了解决多个应用系统之间的用户身份验证问题,提供了便捷的用户体验和安全的身份管理。
2. 多种主要实现用法及其代码示例
2.1 基于Cookie的SSO实现
// SSO服务器端
public class SsoServer {
// 验证登录
public boolean login(String username, String password) {
// 验证用户名和密码是否正确
// ...
// 验证通过后生成Token并存储在服务器端
String token = generateToken();
storeToken(token);
return true;
}
// 生成Token
private String generateToken() {
// ...
}
// 存储Token
private void storeToken(String token) {
// ...
}
}
// 应用系统A
public class AppA {
// 处理用户请求
public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
// 检查是否已登录
if (!checkLogin(request)) {
// 重定向到SSO登录页面
response.sendRedirect("http://sso-server.com/login?redirectUrl=http://app-a.com/callback");
return;
}
// 已登录,继续处理业务逻辑
// ...
}
// 检查是否已登录
private boolean checkLogin(HttpServletRequest request) {
// 从Cookie中获取Token
String token = getTokenFromCookie(request);
// 根据Token向SSO服务器验证登录状态
return validateToken(token);
}
// 从Cookie中获取Token
private String getTokenFromCookie(HttpServletRequest request) {
// ...
}
// 验证Token
private boolean validateToken(String token) {
// ...
}
}
// SSO登录页面
public class SsoLoginPage {
// 处理登录请求
public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 验证用户名和密码
if (ssoServer.login(username, password)) {
// 登录成功,生成Token并重定向到回调URL
String token = generateToken();
String redirectUrl = request.getParameter("redirectUrl") + "?token=" + token;
response.sendRedirect(redirectUrl);
} else {
// 登录失败,返回错误信息
// ...
}
}
}
2.2 基于JWT的SSO实现
// SSO服务器端
public class SsoServer {
// 验证登录
public boolean login(String username, String password) {
// 验证用户名和密码是否正确
// ...
// 验证通过后生成JWT并返回给客户端
String jwt = generateJwt();
return true;
}
// 生成JWT
private String generateJwt() {
// ...
}
}
// 应用系统A
public class AppA {
// 处理用户请求
public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
// 检查是否已登录
if (!checkLogin(request)) {
// 重定向到SSO登录页面
response.sendRedirect("http://sso-server.com/login?redirectUrl=http://app-a.com/callback");
return;
}
// 已登录,继续处理业务逻辑
// ...
}
// 检查是否已登录
private boolean checkLogin(HttpServletRequest request) {
// 从请求头或参数中获取JWT
String jwt = getJwtFromHeaderOrParam(request);
// 根据JWT验证登录状态
return validateJwt(jwt);
}
// 从请求头或参数中获取JWT
private String getJwtFromHeaderOrParam(HttpServletRequest request) {
// ...
}
// 验证JWT
private boolean validateJwt(String jwt) {
// ...
}
}
// SSO登录页面
public class SsoLoginPage {
// 处理登录请求
public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 验证用户名和密码
if (ssoServer.login(username, password)) {
// 登录成功,生成JWT并返回给客户端
String jwt = generateJwt();
response.getWriter().write(jwt);
} else {
// 登录失败,返回错误信息
// ...
}
}
}
3. 其他类似框架
除了自己实现SSO,还有一些开源的SSO框架可供选择,例如:
- CAS(Central Authentication Service):一个用于企业级单点登录的开源框架,提供了完整的SSO解决方案。
- Shibboleth:一个基于SAML协议的身份管理系统,用于实现跨域的单点登录和身份验证。
- OAuth2:一个开放标准的授权协议,可以用于实现SSO以及第三方应用的认证和授权。
4. 详细区别
基于Cookie的SSO实现与基于JWT的SSO实现的区别:
- 认证方式:基于Cookie的SSO使用服务器端存储Token的方式进行认证,而基于JWT的SSO使用无状态的JWT令牌进行认证。
- 安全性:基于Cookie的SSO需要保证Cookie的安全性,防止被窃取或篡改;而基于JWT的SSO通过数字签名保证了令牌的完整性和真实性。
- 扩展性:基于Cookie的SSO在扩展性上受限于Cookie的跨域限制,而基于JWT的SSO可以更灵活地在不同域之间共享令牌。
- 性能:基于Cookie的SSO每次请求都需要携带Cookie,增加了网络传输的开销;而基于JWT的SSO仅需在请求头中携带JWT令牌,减少了传输量。