概念:单点登录(Single Sign-On, SSO)主要是在多个系统、多个浏览器或多个标签页之间共享登录状态,保证用户只需登录一次,就能访问多个关联应用,而不需要重复登录。
💡 方案分类
1. 前端级别 SSO(仅适用于同源)
适用于:同一域名下的多个系统或标签页
方案 | 适用范围 | 共享方式 | 缺点 |
---|---|---|---|
localStorage | 同浏览器、同源 | localStorage 共享 token | 不支持跨浏览器或隐身模式 |
sessionStorage | 仅当前标签页 | sessionStorage | 关闭标签页即失效 |
cookie | 同域、所有浏览器 | 服务器 Set-Cookie | 不能跨域,容量限制 |
BroadcastChannel | 同浏览器、同域 | postMessage 事件广播 | 仅适用于同浏览器 |
2. 前后端结合 SSO(适用于跨域)
适用于:多个子系统,支持不同域名共享登录
方案 | 适用范围 | 共享方式 | 适合场景 |
---|---|---|---|
OAuth 2.0 + JWT | 跨域、多端 | 通过授权服务器获取 token | 第三方登录(微信、GitHub) |
CAS (Central Authentication Service) | 内部系统 | CAS 服务器管理登录态 | 企业内网统一认证 |
SSO + Cookie(SameSite=None + CORS) | 跨子域 | 主域 *.example.com 共享 cookie | 适用于 SaaS 平台 |
SSO + Redis + Session | 跨域 | token 存 Redis,前端查询 | 高并发业务 |
🔹 方案 1:前端 localStorage + BroadcastChannel
(适用于同域)
适用于:同一浏览器的多个标签页
💡 实现思路:
-
登录时,将
token
存入localStorage
并通知其他标签页 -
新标签页打开时,自动获取
localStorage
的token
-
监听
localStorage
变化,保证token
实时同步
// 登录时设置 token
localStorage.setItem('token', 'your-token-value')// 监听 token 变化,保证新打开的页面能同步
window.addEventListener('storage', (event) => {if (event.key === 'token') {console.log('新 token:', event.newValue)}
})
✅ 优点:
-
实现简单
-
无需后端支持
-
适用于同一浏览器、同一域名下的多个系统
❌ 缺点:
-
不能跨浏览器、跨设备共享
-
不能跨域名(如
a.com
无法共享b.com
的token
)
🔹 方案 2:SSO + Cookie 共享(适用于跨子域)
适用于:跨子域(如 admin.example.com
和 user.example.com
)
💡 实现思路:
-
后端设置
cookie
,作用域为*.example.com
-
前端所有子系统 访问
cookie
共享登录状态 -
跨域设置
SameSite=None; Secure
后端(Node.js 示例)
res.cookie('token', 'your-token', {domain: '.example.com', // 设置作用域path: '/',httpOnly: true,secure: true,sameSite: 'None' // 允许跨域
})
前端
fetch('https://auth.example.com/check-login', {credentials: 'include' // 允许跨域携带 Cookie
}).then(res => res.json()).then(data => {console.log('登录状态:', data)})
✅ 优点:
-
支持多个子域共享登录
-
安全性较高
-
用户体验好
❌ 缺点:
-
不能跨主域(如
example.com
不能共享other.com
) -
需要 HTTPS
-
浏览器
SameSite
限制较多
🔹 方案 3:OAuth 2.0 + JWT(适用于跨域、第三方登录)
适用于:多端、第三方应用、社交登录(如 Google、GitHub、微信)
💡 实现思路:
-
用户在 SSO 服务器 登录,返回
token
-
其他系统使用
token
请求 SSO,获取用户信息 -
通过
OAuth
标准协议授权
前端 OAuth 登录
window.location.href = `https://sso.example.com/oauth/authorize?client_id=your-client-id&redirect_uri=${encodeURIComponent(window.location.href)}`
后端验证 token
app.get('/auth/user', async (req, res) => {const token = req.headers.authorization?.split(' ')[1]const user = verifyToken(token) // 解析 JWTres.json(user)
})
✅ 优点:
-
支持跨域、跨设备
-
可用于第三方应用
-
安全性高
❌ 缺点:
-
需要后端支持
OAuth 2.0
-
token
需要存cookie
或localStorage
🔹 方案 4:SSO + Redis + Session(适用于企业系统)
适用于:企业级 SSO(如钉钉、企业微信)
💡 实现思路:
-
用户登录后,后端将
session
存入 Redis -
不同系统请求 SSO,校验
session
是否有效 -
用户登出时,删除 Redis
session
后端
const sessionStore = new Redis() // 连接 Redisapp.post('/login', (req, res) => {const token = generateToken(req.body.user)sessionStore.set(token, JSON.stringify(req.body.user), 'EX', 3600) // 存入 Redisres.json({ token })
})app.get('/check-session', async (req, res) => {const token = req.headers.authorization?.split(' ')[1]const session = await sessionStore.get(token)if (session) {res.json(JSON.parse(session))} else {res.status(401).json({ message: '未登录' })}
})
✅ 优点:
-
可以跨域、跨浏览器共享登录
-
适用于大规模企业级系统
-
支持 SSO 统一管理
❌ 缺点:
-
需要后端支持 Redis
-
实现较复杂
📌 方案对比
方案 | 适用范围 | 共享方式 | 安全性 | 适合场景 |
---|---|---|---|---|
localStorage | 同浏览器 | localStorage | 低 | 前端应用 |
BroadcastChannel | 同浏览器 | postMessage | 低 | 单页面应用 |
Cookie + SameSite | 跨子域 | cookie | 中 | 内部 SaaS 系统 |
OAuth 2.0 + JWT | 跨域、第三方 | token | 高 | 公共平台 |
SSO + Redis | 跨系统、跨浏览器 | session | 高 | 企业 SSO |
🎯 最佳实践
-
小型前端应用(SPA) ➝
localStorage + BroadcastChannel
-
企业 SaaS(跨子域) ➝
Cookie + SameSite=None
-
第三方登录(跨域) ➝
OAuth 2.0 + JWT
-
企业级 SSO(跨浏览器、多系统) ➝
Redis + Session
推荐组合:
✅ SSO + OAuth 2.0 + Redis + JWT,适用于高安全性、多端登录