面试高频考题之双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 应用能够在保证无状态认证的前提下,有效管理会话和身份验证的生命周期。

相关推荐
蒸汽求职8 小时前
跨越 CRUD 内卷:半导体产业链与算力基建下的软件工程新生态
人工智能·科技·面试·职场和发展·软件工程·制造
小兵张健8 小时前
一场大概率没拿到 offer 的面试,让我更坚定去做喜欢的事
人工智能·面试·程序员
AI人工智能+电脑小能手11 小时前
【大白话说Java面试题】【Java基础篇】第7题:HashMap的get流程是什么
java·后端·面试·哈希算法·散列表·hash-index·hash
豹哥学前端13 小时前
别再背“var 提升,let/const 不提升”了:揭开暂时性死区的真实面目
前端·面试
何陋轩13 小时前
【重磅】悟空来了:国产AI编程助手深度测评,能否吊打Copilot?
人工智能·算法·面试
小研说技术15 小时前
实时通信对比,一场MCP协议的技术革命
前端·后端·面试
山栀shanzhi15 小时前
C/C++之:构造函数为什么不能设置为虚函数?
开发语言·c++·面试
我叫黑大帅17 小时前
受保护的海报图片读取方案 - 在不公开静态资源目录下如何获取静态资源
后端·python·面试
逻辑驱动的ken17 小时前
Java高频面试考点场景题11
java·深度学习·面试·职场和发展·高效学习
Rabitebla18 小时前
【数据结构】动态顺序表实现详解:从原理到接口设计(面试视角)
c语言·开发语言·数据结构·c++·面试·职场和发展