vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > 前后端token续期

Vue前后端实现token自动续期的方法详解

作者:高并发吃面

在前后端分离架构中,Token 是实现身份认证的核心机制,但 Token 过期会导致用户操作中断,因此自动续期方案是保障用户持续访问的关键,下面小编就和大家介绍几个主流的 Token 自动续期方案吧

在前后端分离架构中,Token 是实现身份认证的核心机制,但 Token 过期会导致用户操作中断,影响体验。因此,自动续期方案是保障用户持续访问的关键。以下是几种主流的 Token 自动续期方案,包含原理、实现细节及安全性考量。

一、刷新 Token(Refresh Token)机制

这是目前最成熟、应用最广泛的方案,核心是通过“双 Token 体系”实现续期,兼顾安全性和用户体验。

1. 核心原理

当 Access Token 过期时,前端用未过期的 Refresh Token 向后端换取新的 Access Token,避免用户重新登录。

2. 前后端实现流程

前端实现(以 Axios 为例)

1.存储 Token:Access Token 存在内存或 httpOnly Cookie(推荐,防 XSS);Refresh Token 存在 httpOnly Cookie(避免前端 JS 读取,增强安全性)。

2.请求拦截器:每次请求在 Header 中携带 Access Token(如 Authorization: Bearer {accessToken})。

3.响应拦截器:处理 401 错误(Access Token 过期):

// 响应拦截器示例
axios.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // 若为401且未尝试过刷新
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true; // 标记已尝试刷新,避免重复请求
      try {
        // 调用刷新接口(Refresh Token 通过 Cookie 自动携带)
        const { data } = await axios.post('/api/refresh-token');
        // 更新本地 Access Token
        localStorage.setItem('accessToken', data.accessToken);
        // 重试原请求(携带新 Token)
        originalRequest.headers['Authorization'] = `Bearer ${data.accessToken}`;
        return axios(originalRequest);
      } catch (refreshError) {
        // 刷新失败(Refresh Token 过期),跳转登录
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }
    return Promise.reject(error);
  }
);

4.并发请求处理:若多个请求同时触发 401,需避免重复刷新 Token。可通过“锁机制”实现:刷新过程中阻塞其他请求,等待新 Token 生成后统一重试。

后端实现

1.生成 Token:登录成功时,同时生成 Access Token(短期)和 Refresh Token(长期),返回给前端(Access Token 可放响应体,Refresh Token 放 httpOnly Cookie)。

2.验证 Access Token:接口请求时,验证 Access Token 的签名和有效期,无效则返回 401。

3.刷新接口实现

// 后端刷新接口示例(伪代码)
@PostMapping("/api/refresh-token")
public Result refreshToken(HttpServletRequest request) {
  // 从 Cookie 获取 Refresh Token
  String refreshToken = CookieUtils.getCookieValue(request, "refreshToken");
  if (refreshToken == null) {
    return Result.fail(401, "刷新令牌不存在");
  }
  // 验证 Refresh Token(查库+验签)
  RefreshTokenEntity entity = refreshTokenMapper.selectByToken(refreshToken);
  if (entity == null || entity.getExpireTime().before(new Date())) {
    return Result.fail(401, "刷新令牌已过期");
  }
  // 生成新 Access Token 和 Refresh Token
  String newAccessToken = JwtUtils.generateAccessToken(entity.getUserId());
  String newRefreshToken = JwtUtils.generateRefreshToken(entity.getUserId());
  // 更新数据库中的 Refresh Token(旧的标记失效,存储新的)
  refreshTokenMapper.invalidateOldToken(entity.getId());
  refreshTokenMapper.insert(new RefreshTokenEntity(newRefreshToken, entity.getUserId()));
  // 返回新 Token(Access Token 放响应体,Refresh Token 放 httpOnly Cookie)
  return Result.success(Map.of(
    "accessToken", newAccessToken,
    "refreshToken", newRefreshToken // 可选,通过 Cookie 返回更安全
  ));
}

3. 优缺点

二、滑动窗口续期(无 Refresh Token)

适用于对安全性要求中等、希望简化实现的场景,核心是“Token 快过期时自动延长有效期”。

1. 核心原理

2. 前后端实现流程

前端实现

存储 Token 并在请求头携带。

每次收到响应后,检查是否包含新 Token(如响应头 X-New-Token),若有则更新本地存储。

// 响应拦截器示例
axios.interceptors.response.use(
  (response) => {
    // 若响应头有新 Token,更新本地存储
    const newToken = response.headers['x-new-token'];
    if (newToken) {
      localStorage.setItem('accessToken', newToken); // 建议用 Cookie
    }
    return response;
  },
  (error) => {
    // 若 Token 已过期(401),直接跳转登录
    if (error.response?.status === 401) {
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

后端实现

Token 中包含过期时间(如 exp 字段)。

每次验证 Token 时,计算剩余有效期:若剩余时间 < 阈值(如 10 分钟),则生成新 Token,放在响应头(如 X-New-Token)返回。

// 验证 Token 并判断是否续期(伪代码)
public String validateAndRenewToken(String token) {
  // 验证 Token 签名和有效性
  Claims claims = JwtUtils.parseToken(token);
  if (claims == null) {
    throw new TokenInvalidException();
  }
  // 计算剩余有效期(当前时间到 exp 的差值)
  long expireTime = claims.getExpiration().getTime();
  long remainingTime = expireTime - System.currentTimeMillis();
  // 若剩余时间 < 10 分钟,生成新 Token
  if (remainingTime < 10 * 60 * 1000) {
    String newToken = JwtUtils.generateAccessToken(claims.getSubject()); // 用原用户 ID 生成新 Token
    return newToken;
  }
  return null; // 无需续期
}

3. 优缺点

三、主动预检续期

适用于对请求成功率要求高的场景,前端主动检测 Token 有效期,提前续期。

1. 核心原理

2. 前后端实现流程

前端实现(请求拦截器中处理)

axios.interceptors.request.use(async (config) => {
  const token = localStorage.getItem('accessToken');
  if (!token) {
    window.location.href = '/login';
    return Promise.reject(new Error('未登录'));
  }
  // 解析 Token 中的过期时间(需前端解析 JWT,或后端返回过期时间)
  const payload = JSON.parse(atob(token.split('.')[1]));
  const expireTime = payload.exp * 1000; // JWT 的 exp 是秒级时间戳
  const remainingTime = expireTime - Date.now();
  
  // 若剩余时间 ≤ 5 分钟,先续期
  if (remainingTime <= 5 * 60 * 1000) {
    try {
      const { data } = await axios.post('/api/renew-token', { token });
      const newToken = data.newToken;
      localStorage.setItem('accessToken', newToken);
      config.headers['Authorization'] = `Bearer ${newToken}`;
    } catch (error) {
      // 续期失败,跳转登录
      window.location.href = '/login';
      return Promise.reject(error);
    }
  } else {
    config.headers['Authorization'] = `Bearer ${token}`;
  }
  return config;
});

后端实现

3. 优缺点

四、安全性与最佳实践

Token 存储

过期时间设置

Refresh Token 轮换:每次用 Refresh Token 换取新 Access Token 时,同步生成新的 Refresh Token(旧的立即失效),防止 Refresh Token 被复用。

HTTPS 传输:所有 Token 必须通过 HTTPS 传输,防止中间人攻击。

并发请求处理:用“锁机制”(如 Promise 等待)处理多个请求同时触发续期的场景,避免重复调用刷新接口。

Token 吊销:后端需支持主动吊销 Token(如用户登出、修改密码时),可通过“黑名单”(Redis 存储已吊销 Token)实现快速验证。

总结

实际场景中,可结合业务需求(如用户活跃度、安全等级)选择方案,核心是在“用户体验”与“安全性”之间找到平衡。

到此这篇关于Vue前后端实现token自动续期的方法详解的文章就介绍到这了,更多相关前后端token续期内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文