行业资讯
📅 2026/8/9 11:25:08
基于Cookie域共享的轻量级SSO实现方案
1. 域登录态分享技术解析在企业级应用架构中登录态共享通常称为SSOSingle Sign-On是一个关键的基础设施能力。最近我在重构公司内部系统时实现了一套轻量级的域登录态共享方案这里分享下具体实现思路和踩坑经验。传统的SSO方案往往需要引入复杂的中间件而我们的需求是在同一个主域下的多个子系统间实现登录态共享。这种场景在中小型企业内部系统中非常常见——比如OA系统、CRM系统、内部知识库等需要统一认证但又不想部署全套SSO的情况。2. 核心原理与设计方案2.1 Cookie的作用域机制实现域登录态共享的基础是浏览器的Cookie作用域机制。当我们在example.com域下设置Cookie时Set-Cookie: auth_tokenabc123; Domain.example.com; Path/; HttpOnly; Secure这个Cookie会自动共享给所有*.example.com的子域名如oa.example.com、crm.example.com。这是HTTP协议的标准行为也是我们方案的技术基础。2.2 认证中心设计我们建立了一个专门的认证子域auth.example.com负责处理所有登录/注销请求颁发包含用户身份的JWT令牌维护会话状态关键代码示例Node.js// 登录成功后设置跨域Cookie router.post(/login, async (ctx) { const { username, password } ctx.request.body; const user await validateUser(username, password); if (user) { const token generateJWT(user); ctx.cookies.set(auth_token, token, { domain: .example.com, httpOnly: true, secure: true, maxAge: 8 * 60 * 60 * 1000 // 8小时 }); ctx.body { success: true }; } else { ctx.status 401; } });3. 完整实现流程3.1 系统架构用户浏览器 │ ├─ auth.example.com (认证中心) │ ├─ /login │ ├─ /logout │ └─ /validate │ ├─ app1.example.com (业务系统1) │ └─ 依赖auth_token │ └─ app2.example.com (业务系统2) └─ 依赖auth_token3.2 前端集成方案在每个子系统的前端页面需要检查是否存在auth_token如果没有则跳转到auth.example.com/login登录成功后回跳原页面示例前端检查逻辑// 在所有子系统前端入口处添加 if (!document.cookie.includes(auth_token)) { const redirectUri encodeURIComponent(window.location.href); window.location.href https://auth.example.com/login?redirect${redirectUri}; }3.3 后端验证中间件每个业务系统需要添加一个验证中间件const jwt require(jsonwebtoken); async function authMiddleware(ctx, next) { const token ctx.cookies.get(auth_token); try { const decoded jwt.verify(token, process.env.JWT_SECRET); ctx.state.user decoded; await next(); } catch (err) { ctx.redirect(https://auth.example.com/login?redirect${encodeURIComponent(ctx.url)}); } }4. 安全增强措施4.1 CSRF防护虽然HttpOnly Cookie可以防止XSS攻击但仍需防范CSRF为敏感操作添加CSRF Token检查Origin/Referer头部// CSRF Token生成 const csrf require(csrf); const tokens new csrf(); router.get(/csrf-token, (ctx) { ctx.body { token: tokens.create(process.env.CSRF_SECRET) }; });4.2 会话管理实现以下安全策略令牌有效期8小时注销时清除Cookie和服务端会话记录登录设备信息// 注销处理 router.post(/logout, (ctx) { ctx.cookies.set(auth_token, null, { domain: .example.com, expires: new Date(0) }); ctx.body { success: true }; });5. 常见问题与解决方案5.1 跨域Cookie问题现象Safari浏览器下Cookie设置失败解决确保Domain属性包含前导点.example.com检查SameSite属性设置建议Lax5.2 登录循环现象不断重定向到登录页排查检查Cookie作用域设置验证JWT签名密钥是否一致检查系统时间是否同步5.3 性能优化对于高并发系统使用Redis缓存会话信息JWT采用非对称加密RS256实现令牌自动续期// Redis会话存储示例 const redis require(redis); const client redis.createClient(); async function validateToken(token) { const cached await client.get(session:${token}); if (cached) return JSON.parse(cached); const decoded jwt.verify(token, process.env.JWT_SECRET); await client.setex(session:${token}, 28800, JSON.stringify(decoded)); return decoded; }6. 扩展方案当需要支持完全独立的第三方域名时可以考虑OAuth 2.0授权码模式基于iframe的postMessage通信专门的网关代理方案graph TD A[第三方网站] --|1. 发起授权请求| B(auth.example.com) B --|2. 返回授权码| A A --|3. 用授权码换令牌| C(API Gateway) C --|4. 返回JWT| A A --|5. 存储令牌| D[LocalStorage]不过这些方案实现复杂度会显著增加应根据实际需求评估。对于大多数内部系统场景基于Cookie的域共享方案已经足够。