面试高频考题之双token机制💻

引言💭

在之前的文章Web身份认证与状态管理:Cookie、Session 与 JWT中提到了JWT,这篇文章再来介绍一下它的进阶版本,双Token机制。


一、什么是双 Token 机制?🤔

双 Token 机制是一种通过使用两种不同类型的令牌来管理用户身份认证和授权的方案。通常,这两种令牌是:

  1. Access Token(访问令牌):用于身份验证和授权,通常有效期较短,用于每次请求时的验证。
  2. Refresh Token(刷新令牌):用于获取新的 Access Token,通常有效期较长,帮助用户在 Access Token 过期后无缝继续访问应用。

二、JWT 与双 Token 机制的关系👥

JWT(JSON Web Token)是一种常用的令牌格式,广泛用于双 Token 机制中的 Access Token 实现。JWT 采用签名技术,确保数据的完整性和安全性。其结构由三部分组成:

  • Header(头部) :指定令牌的类型(JWT)和签名算法。
  • Payload(负载) :包含声明信息,如用户身份标识(sub)、过期时间(exp)等。
  • Signature(签名) :使用密钥对前两部分进行签名,用来验证数据完整性和防止篡改。

因此,在双 Token 机制中,Access Token 通常采用 JWT 格式,而 Refresh Token 则是另一个长期有效的令牌。两者结合使用,能够提供高效且安全的认证方案。


三、双 Token 的工作流程📌

双 Token 机制的工作流程如下:

  1. 用户登录 :用户通过用户名和密码登录系统,服务器验证用户身份后,生成并返回 Access TokenRefresh Token
  2. 访问受保护资源 :客户端使用 Access Token 向服务器请求资源,服务器验证 Access Token 的有效性。
  3. Access Token 过期 :当 Access Token 过期时,客户端通过 Refresh Token 请求新的 Access Token,无需重新登录。
  4. 获取新 Access Token :服务器验证 Refresh Token 的有效性后,返回新的 Access Token,客户端继续访问受保护资源。
  5. Refresh Token 过期 :如果 Refresh Token 过期,用户需要重新登录,重新获取新的 Access TokenRefresh Token

四、双 Token 机制的优势✨

1. 提高安全性

Access Token 存储在内存中可以减少暴露风险,因为内存中的数据在页面刷新时会清空。由于 Access Token 有较短的有效期,这样的存储方式非常适合短期使用。

Refresh Token 存储在带有 HttpOnly 属性的 cookie 中,则有效阻止了 JavaScript 访问该 token,增加了安全性。这种方法通常用于防止 XSS 攻击,使得即使攻击者能够执行 JavaScript 代码,也无法窃取 token。

这种方式结合了安全性和便捷性,确保了 Access Token 的短期使用和 Refresh Token 的长期存储在安全的位置,从而平衡了用户体验与安全性。

2. 无缝用户体验

使用 Refresh Token 可以避免用户在 Access Token 过期时重新登录。只要 Refresh Token 仍然有效,客户端就能自动获取新的 Access Token,提供无缝的用户体验,尤其适合需要长时间在线的应用,如社交媒体或电商平台。

3. 无状态认证

JWT 是无状态的,意味着服务器不需要存储会话信息。所有身份和权限信息都封装在 JWT 中,通过验证签名和有效期来确保请求的合法性。双 Token 机制进一步增强了这一点,服务器只需存储 Refresh Token,而无需管理用户的会话状态。


五、如何实现双 Token 机制?🤔

1. 生成 JWT Access Token 和 Refresh Token

使用 JWT 库生成 Access TokenRefresh Token

  • Access Token 通常包含用户的身份信息和过期时间,签名用于验证其完整性。
  • Refresh Token 长期有效,用于刷新 Access Token

代码示例:

perl 复制代码
const jwt = require('jsonwebtoken');

// 生成 Access Token
function generateAccessToken(user) {
  return jwt.sign(
  { sub: user.id }, 
  'secret', 
  { expiresIn: '15m' } // 短时效
  );
}

// 生成 Refresh Token
function generateRefreshToken(user) {
  return jwt.sign(
  { sub: user.id },
  'refreshSecret', 
  { expiresIn: '7d' } // 长时效
  );
}

2. 存储 Refresh Token

Refresh Token 可以存储在服务器端的数据库中,或通过安全的方式(如 HTTPOnly cookies)存储在客户端。它的有效期通常较长。

3. 验证 Access Token

每次客户端发起请求时,Access Token 会包含在 HTTP 头部的 Authorization 字段中,服务器通过验证其有效性来判断请求是否合法。

scss 复制代码
// 验证 Access Token
function verifyAccessToken(req, res, next) {
  // 获取 Bearer Token 的第二部分(实际 Token 值)
  const token = req.headers['authorization']?.split(' ')[1]; 
  if (!token) return res.status(403).send('Access denied.'); // 验证token是否存在
  
  // 验证token
  jwt.verify(token, 'secret', (err, user) => {
    if (err) return res.status(403).send('Invalid or expired token.');
    req.user = user; // 将解码后的用户信息(payload)附加到 `req.user` 上
    next();
  });
}

4. 使用 Refresh Token 刷新 Access Token

Access Token 过期时,客户端将 Refresh Token 发送到服务器,服务器验证 Refresh Token 后生成新的 Access Token

scss 复制代码
// 使用 Refresh Token 刷新 Access Token
function refreshAccessToken(req, res) {
  // 从请求体(body)中获取客户端提交的 refreshToken
  const refreshToken = req.body.refreshToken;
  // 检查 Refresh Token 是否存在
  if (!refreshToken) return res.status(403).send('Refresh Token required.');
  
  // 验证 Refresh Token
  jwt.verify(refreshToken, 'refreshSecret', (err, user) => {
    if (err) return res.status(403).send('Invalid refresh token.');

    // 调用 generateAccessToken 函数生成新的 Access Token 并返回给客户端
    const newAccessToken = generateAccessToken(user);
    res.json({ accessToken: newAccessToken });
  });
}

结语✒️

双 Token 机制结合了 Access TokenRefresh Token 的优势,既保证了安全性,又提升了用户体验。它使得 Web 应用能够在保证无状态认证的前提下,有效管理会话和身份验证的生命周期。

相关推荐
spionbo18 分钟前
Vue 表情包输入组件实现代码及完整开发流程解析
前端·javascript·面试
天涯学馆32 分钟前
前后端分离的 API 设计:技术深度剖析
前端·javascript·面试
异常君1 小时前
Spring 中的 FactoryBean 与 BeanFactory:核心概念深度解析
java·spring·面试
异常君2 小时前
Java 中 try-catch 的性能真相:全面分析与最佳实践
java·面试·代码规范
程序员清风3 小时前
阿里二面:Kafka 消费者消费消息慢(10 多分钟),会对 Kafka 有什么影响?
java·后端·面试
wandongle3 小时前
HTML 面试题错题总结与解析
前端·面试·html
MrSkye4 小时前
🚀 由Tony Stark 带你入门 JavaScript(新手向)🚀
前端·javascript·面试
掘金安东尼4 小时前
仅仅是发送一封邮件?暴露安全边界!
javascript·vue.js·面试
_一条咸鱼_4 小时前
Android Runtime类卸载条件与资源回收策略(29)
android·面试·android jetpack
顾林海4 小时前
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
android·面试·性能优化