You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React.js中如何利用Cookie内的Refresh Token刷新Access Token?

Access/Refresh Token机制及前端刷新实现指南

一、Access Token与Refresh Token通用运行机制

核心是平衡安全性和用户体验,流程如下:

  • 首次登录:用户提交账号密码到认证服务器,验证通过后生成两个Token:
    • Access Token:短期有效(建议15-30分钟),用于调用业务接口,需放在请求头Authorization: Bearer xxx中。
    • Refresh Token:长期有效(建议7-30天),仅用于向认证服务器获取新的Access Token,通常存入HttpOnly、Secure的Cookie(防止前端JS读取,规避XSS风险)。
  • 日常请求:前端调用业务接口时携带Access Token,业务服务器校验Token的签名、过期时间,有效则处理请求,无效返回401。
  • 刷新流程:当Access Token过期(接口返回401),前端触发刷新请求,浏览器自动携带Cookie中的Refresh Token到认证服务器;服务器校验通过后返回新的Access Token(可选同步更新Refresh Token);若Refresh Token也过期,直接引导用户重新登录。

二、利用Cookie中的Refresh Token刷新Access Token

后端配置(Node.js)

将Refresh Token设置为HttpOnly Cookie,确保前端无法通过JS读取,仅由浏览器自动携带:

// 登录成功后设置Refresh Token Cookie
res.cookie('refreshToken', generatedRefreshToken, {
  httpOnly: true, // 关键:禁止前端JS读取
  secure: process.env.NODE_ENV === 'production', // 生产环境仅HTTPS传输
  sameSite: 'strict', // 防范CSRF攻击
  maxAge: 30 * 24 * 60 * 60 * 1000 // 30天有效期
});

前端实现(React.js)

无需手动读取Cookie,直接调用刷新接口即可,浏览器会自动携带Refresh Token:

// 示例:Axios请求刷新Token
async function refreshAccessToken() {
  try {
    const response = await axios.post('/api/auth/refresh');
    return response.data.accessToken; // 获取新的Access Token
  } catch (error) {
    // 刷新失败,跳转登录页
    window.location.href = '/login';
    throw error;
  }
}

三、前端刷新请求的频率与性能优化(避免内存泄漏)

为什么不推荐固定setInterval

固定时间间隔的setInterval会引发一系列问题:

  • 不必要的请求:用户退出或Token已刷新后,定时器仍在运行。
  • 内存泄漏:组件卸载时未清除定时器,导致定时器持续占用内存。
  • 性能下降:频繁触发定时器+状态更新,引发不必要的组件重渲染。

推荐两种优化方案

1. 接口拦截器按需刷新(最优)

在Axios/Fetch的响应拦截器中统一处理401,仅当接口返回Token过期时触发刷新,完全按需:

// Axios响应拦截器示例
axios.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // 避免刷新接口本身的401导致死循环
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      try {
        const newAccessToken = await refreshAccessToken();
        // 更新全局请求头的Token
        axios.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;
        // 重新发起原请求
        return axios(originalRequest);
      } catch (refreshError) {
        return Promise.reject(refreshError);
      }
    }
    return Promise.reject(error);
  }
);

2. 基于Token过期时间的延迟刷新(提前刷新场景)

若需提前刷新(比如提前5分钟),用setTimeout替代setInterval,且在组件卸载时清除定时器:

import { useEffect, useState } from 'react';
import axios from 'axios';

function AuthComponent() {
  const [accessToken, setAccessToken] = useState(localStorage.getItem('accessToken'));

  useEffect(() => {
    let timeoutId;
    if (accessToken) {
      // 解析JWT的过期时间(JWT payload为base64编码)
      const payload = JSON.parse(atob(accessToken.split('.')[1]));
      const expiresTimestamp = payload.exp * 1000; // exp是秒级时间戳,转毫秒
      const refreshTime = expiresTimestamp - Date.now() - 5 * 60 * 1000; // 提前5分钟刷新

      if (refreshTime > 0) {
        timeoutId = setTimeout(async () => {
          const newToken = await refreshAccessToken();
          setAccessToken(newToken);
          localStorage.setItem('accessToken', newToken);
        }, refreshTime);
      }
    }

    // 组件卸载时清除定时器,避免内存泄漏
    return () => {
      if (timeoutId) clearTimeout(timeoutId);
    };
  }, [accessToken]);

  // ...其他组件逻辑
}

这种方式每次Access Token更新后会重新计算超时时间,仅维持一个定时器运行,不会出现叠加问题,也能规避内存泄漏。

内容的提问来源于stack exchange,提问作者ILOVEJSON

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 22:12:41