写点什么

现代 Web 安全实践:基于 Token 与 Refresh Token 的单点登录 (SSO) 实现

作者:袋鼠云数栈
  • 2025-07-01
    浙江
  • 本文字数:2222 字

    阅读完需:约 7 分钟

现代 Web 安全实践:基于 Token 与 Refresh Token 的单点登录 (SSO) 实现

在数字化转型加速的今天,单点登录 (SSO) 已成为企业身份管理的核心基础设施。袋鼠云 UED 团队在过去几年中,为金融、政务、医疗等领域的大型系统构建 SSO 解决方案。本文将分享基于 Token 的标准 SSO 实现,同时解密 UED 团队对于单点登录的安全实践方式。


单点登录核心原理

1、SSO 的基本工作流程


2、双 Token 机制的优势


  • Access Token:短期有效 (通常 1-2 小时),减少泄露风险

  • Refresh Token:长期有效 (通常 7-30 天),存储于 HttpOnly Cookie 中

  • 安全平衡:即使 Access Token 泄露,攻击者也难以获取新的有效 Token


Node.js + JWT 实现示例 1、认证服务核心代码

1、认证服务核心代码


const jwt = require('jsonwebtoken');const crypto = require('crypto');


// 生成密钥对(实际项目应该预生成并妥善保存)const {privateKey, publicKey} = crypto.generateKeyPairSync ('rsa', { modulusLength: 2048,});


// 生成 Tokenfunction generateTokens (user) { const accessToken = jwt.sign ( { userId: user.id, role: user.role }, privateKey, { algorithm: 'RS256', expiresIn: '1h' } );


const refreshToken = jwt.sign( { userId: user.id, tokenVersion: user.tokenVersion }, privateKey, { algorithm: 'RS256', expiresIn: '7d' } );


return { accessToken, refreshToken };}


// 验证中间件 function authenticate (req, res, next) { const authHeader = req.headers ['authorization']; const token = authHeader && authHeader.split (' ')[1];


if (!token) return res.sendStatus(401);


jwt.verify(token, publicKey, (err, user) => { if (err) return res.sendStatus(403); req.user = user; next(); });}


2、Token 刷新接口设计


app.post('/refresh-token', (req, res) => { const refreshToken = req.cookies.refreshToken;


if (!refreshToken) return res.sendStatus(401);


jwt.verify(refreshToken, publicKey, async (err, payload) => { if (err) return res.sendStatus(403);


// 检查数据库中的 token 版本(防止被盗用) const user = await User.findById (payload.userId); if (user.tokenVersion !== payload.tokenVersion) { return res.sendStatus (403); }


// 颁发新 Token const newTokens = generateTokens (user);


// 设置 HttpOnly Cookie res.cookie ('refreshToken', newTokens.refreshToken, { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 7 * 24 * 60 * 60 * 1000});


res.json({ accessToken: newTokens.accessToken }); });});


前端实现关键点

1、Axios 拦截器配置


const api = axios.create({ baseURL: process.env.API_URL,});


// 请求拦截器 api.interceptors.request.use (config => { const token = localStorage.getItem ('accessToken'); if (token) { config.headers.Authorization = Bearer ${token}; } return config;});


// 响应拦截器 api.interceptors.response.use (response => response, async error => { const originalRequest = error.config;


// 401 错误且不是刷新请求 if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true;


try {const { data} = await axios.post ('/refresh-token', {}, { withCredentials: true // 携带 cookie });


localStorage.setItem ('accessToken', data.accessToken); originalRequest.headers.Authorization = Bearer ${data.accessToken}; return api (originalRequest); } catch (refreshError) { // 刷新失败跳转登录 window.location = '/login'; return Promise.reject (refreshError); } }


return Promise.reject(error); });


2、安全存储方案对比


安全增强措施

1、Token 撤销策略


2、多因素认证集成


app.post('/login', async (req, res) => { const { email, password } = req.body;


const user = await User.findOne ({email}); if (!user || !await bcrypt.compare (password, user.password)) { return res.status (401).send (' 认证失败 '); }


// 检查是否开启 MFA if (user.mfaEnabled) { const tempToken = jwt.sign ( { userId: user.id, mfa: true }, privateKey, { expiresIn: '5m' } ); return res.json({ mfaRequired: true, tempToken }); }


// 常规登录流程 const tokens = generateTokens (user); sendTokens (res, tokens);});


app.post('/verify-mfa', authenticateTempToken, (req, res) => { const { code } = req.body;


if (verifyMfaCode (req.user.userId, code)) { const user = await User.findById (req.user.userId); const tokens = generateTokens (user); sendTokens (res, tokens); } else { res.status (401).send ('MFA 验证失败 '); }});


最佳实践建议

1、传输安全


  • 始终使用 HTTPS

  • 设置 SecureSameSiteCookie 属性


2、防御措施


  • 实现 CSRF Token 机制

  • 设置速率限制(如 1 分钟 5 次刷新)


3、监控审计


4、失效处理

  • 登出时清除客户端 Token

  • 服务端维护短期黑名单(JWT 本身无状态)


Token 与 Refresh Token 机制为现代 SSO 提供了优雅的解决方案。作为袋鼠云技术团队,我们在多个项目中验证了这一架构的可靠性,Token+RefreshToken 方案在安全性和用户体验之间取得了良好平衡。实际部署时还需要考虑:


  • 分布式环境下的密钥管理

  • 多平台 Token 同步

  • 会话超时策略


建议结合 OAuth 2.0 或 OpenID Connect 等标准协议实现生产级 SSO 系统。

用户头像

还未添加个人签名 2021-05-06 加入

还未添加个人简介

评论

发布
暂无评论
现代 Web 安全实践:基于 Token 与 Refresh Token 的单点登录 (SSO) 实现_Web_袋鼠云数栈_InfoQ写作社区