你用公司工卡刷开写字楼大门后,进会议室不用刷卡,喝咖啡不用刷卡,连打印文件都不再扫码登录——这就是单点登录(SSO) 。
一、为什么要用SSO?痛点即价值
场景还原:早晨9点,产品经理打开5个系统:
journey
title 没有SSO的灾难现场
section 登录地狱
打卡系统 --> 输入账号密码: 20秒
CRM系统 --> 重新输入密码: 30秒(忘记密码)
报销系统 --> 验证短信验证码: 40秒
数据平台 --> 扫码认证: 1分钟
邮件系统 --> 密码错误锁定: 崩溃!
SSO带来三大变革:
- 用户体验:1次登录畅行所有关联系统(登录耗时↓90%)
- 安全加固:统一安全策略(多因素认证/异地登录检测)
- 运维成本:用户生命周期管理成本↓50%(禁用账号一键生效)
根据OWASP报告,采用SSO的企业内部系统安全事件减少68%
二、SSO核心原理
以电商系统(主站+订单中心+物流系统)为例:
sequenceDiagram
用户->>认证中心: 访问主站
认证中心-->>用户: 重定向到登录页
用户->>认证中心: 输入账号密码
认证中心->>用户: 颁发加密令牌(JWT)
用户->>订单系统: 携带令牌访问
订单系统->>认证中心: 验证令牌有效性
认证中心-->>订单系统: 返回用户信息
订单系统-->>用户: 展示订单页面
关键角色:
- 认证中心:唯一登录入口(SSO的核心大脑)
- 业务系统:依赖令牌验证用户身份(不存储密码)
- 令牌:用户身份的加密通行证(常用JWT)
三、技术方案对比
| 方案 | 适用场景 | 安全性 | 复杂度 | 典型案例 |
|---|---|---|---|---|
| Cookie+Token | 同域名系统 | ★★★☆ | ★★☆ | 企业内网门户 |
| JWT | 跨域分布式系统 | ★★★★ | ★★★ | 电商平台 |
| OAuth2.0 | 第三方授权登录 | ★★★★★ | ★★★★ | 微信/Google登录 |
| SAML | 企业级认证 | ★★★★★ | ★★★★☆ | 银行/政府系统 |
选型建议:
- 内部系统:JWT方案(平衡安全与成本)
- 开放平台:OAuth2.0(第三方接入首选)
- 金融系统:SAML(企业级安全标准)
四、实战:JWT方案10步落地
步骤1 - 登录请求转发(前端)
// 用户尝试访问订单系统时
if (!checkLocalToken()) {
// 重定向到认证中心登录页
window.location.href = `https://sso.com/login?redirect_url=${encodeURIComponent(location.href)}`;
}
步骤2 - 认证中心颁发令牌(后端)
// 验证账号密码后生成JWT
const token = jwt.sign(
{ userId: 'u001', role: 'vip' },
RSA_PRIVATE_KEY,
{ expiresIn: '2h', algorithm: 'RS256' }
);
// 种下跨域Cookie(主域名相同)
res.cookie('sso_token', token, {
domain: '.company.com',
httpOnly: true,
secure: true
});
步骤3 - 业务系统验证令牌(Node.js中间件)
app.use(async (req, res, next) => {
const token = req.cookies.sso_token;
try {
// RSA公钥解密验证
const decoded = jwt.verify(token, RSA_PUBLIC_KEY);
req.user = await User.findById(decoded.userId);
next();
} catch (err) {
res.redirect('https://sso.com/login?service=' + req.url);
}
});
安全增强:
加入JWT黑名单机制,退出登录时立即失效令牌
五、避坑指南
1. 同源策略陷阱
问题:Chrome默认禁止跨域Cookie
方案:主域名统一 + Nginx反向代理
# Nginx配置统一域名
server {
listen 80;
server_name *.company.com;
location / {
proxy_pass http://localhost:3000;
}
}
2. 令牌劫持防御
攻击场景:XSS获取localStorage中的JWT
方案:
// 前端存储方案升级
const storage = () => {
try {
// 尝试访问httpOnly Cookie
document.cookie;
return localStorage; // 安全环境
} catch {
return { // 降级方案
getItem: () => sessionStorage.getItem('temp_token'),
setItem: (k,v) => sessionStorage.setItem(k,v)
};
}
};
3. 退出登录
痛点:用户退出需通知所有系统
方案:广播登出事件
// 认证中心广播机制
const logoutNotifier = new EventEmitter();
// 业务系统订阅
logoutNotifier.on('user_logout', (userId) => {
clearUserSession(userId);
});
// 前端监听
const eventSource = new EventSource('/logout-events');
eventSource.onmessage = (e) => {
if (e.data === 'force_logout') location.reload();
};
六、升级挑战:分布式系统下的SSO架构
500万用户电商平台方案:
graph LR
A[客户端] --> B[SSO网关]
B --> C{JWT验证集群}
C --> D[Redis令牌池]
D --> E[用户数据库]
E --> F[审计服务]
style B stroke:#f66,stroke-width:2px
三大优化策略:
- 令牌分区存储:按用户ID哈希分片Redis集群
- 动态令牌轮换:每小时生成新令牌(旧令牌并行有效5分钟)
- 多级缓存:本地内存缓存高频用户数据
七、该不该上SSO?
graph TD
A[系统数量>2?] -->|否| B[无需SSO]
A -->|是| C{用户重合度>60%?}
C -->|否| D[独立认证更优]
C -->|是| E[强烈建议SSO]
E --> F{需第三方登录?}
F -->|是| G[选OAuth2]
F -->|否| H[选JWT/Token]
何时应暂缓实施:
- 遗留系统使用COBOL等古董技术
- 合规要求禁止集中存储认证数据
- 系统间信任等级差异过大
SSO不是银弹,但却是系统进化的必经之路。三条黄金法则:
- 信任最小化:业务系统不直接接触密码
- 防御纵深化:令牌加密+传输加密+行为审计
- 降级人性化:单点登录失败时保留独立登录入口