前端必备 | 一文掌握React的Token管理

写在前面

Token管理 是每一个前端程序员都必须面对的问题,但是如果有一个Token管理模板使我们每次着手一个新项目时都可以傻瓜式管理Token ,那么将可以减轻我们的很多压力,本文就介绍一个React的Token管理模式------ Redux+localStorage

直接开始

一、封装Token工具

封装一些Token工具,可以节省很多的代码量。也使代码更加规范化 ,最常用的Token操作有存储(登录时获取),拿取(请求其它接口时校验Token),删除(退出登录时删除)

js 复制代码
//封装和token相关的方法 存 取 删
const TOKEN_KEY = 'token_key'
function setToken(token) {
  localStorage.setItem(TOKEN_KEY, token)
}
function getToken() {
  return localStorage.getItem(TOKEN_KEY)
}
function removeToken() {
  localStorage.removeItem(TOKEN_KEY)
}
export { setToken, getToken, removeToken }

二、获取用户Token

获取用户Token一般发生在用户登录验证完成之后

js 复制代码
// 和用户相关的状态管理
import {createSlice} from '@reduxjs/toolkit'
import { setToken as _setToken , getToken,removeToken } from '@/utils'
import { loginAPI,getProfileAPI } from '@/apis/user'
const userStore=createSlice({
  name: 'user',
  initialState: {
    token: getToken() ||'',
    userInfo: {}
  },
  reducers: {
    setToken(state, action) {
      state.token = action.payload
      // 持久化存储token
      _setToken(action.payload)
    },
    setUserInfo(state, action) {
      state.userInfo = action.payload
    },
    clearUserInfo(state) {
      state.userInfo = {}
      state.token = ''
      removeToken()
    }
    
   }
})

//解构出actionCreators

const {setToken,setUserInfo,clearUserInfo} = userStore.actions
//获取reducer函数
const userReducer = userStore.reducer

//异步方法 完成登录获取token
const fetchLogin=(loginForm)=>{
    return async (dispatch)=>{
        //1.发送异步请求
        const res=await loginAPI(loginForm)
        //2.提交同步action进行token的存入
        dispatch(setToken(res.data.token))
    }
}

//获取个人信息异步方法
const fetchUserInfo=()=>{
    return async (dispatch)=>{
        const res=await getProfileAPI()
        dispatch(setUserInfo(res.data))
    }
}

export {fetchLogin,setToken,fetchUserInfo,clearUserInfo}
export default userReducer

我们在用户的状态管理代码中(Redux)对Token的获取进行了进一步封装(fetchLogin(loginForm))这样做的好处是可以一步到位地完成Token在Redux和localStorage中的存储,而且刷新之后Redux中的Token不为空 ,之后只需在用户点击登录按钮时调用fetchLogin(loginForm)即可实现用户Token的获取,如下

js 复制代码
  const onFinish = async(values) => {
   console.log(values) 
   // 触发action fetchLogin
   await dispatch(fetchLogin(values))
   //1.跳转到首页
   navigate('/')
   //2.提示一下用户
   message.success('登录成功')
  }

三、在axios中使用Token

这部分的代码基本上在哪个项目中都是固定的,这里只是展示一种方案

jsx 复制代码
//axios的封装处理
import axios from 'axios'
import { getToken } from '@/utils'
import router from '@/router'
// 1.根域名配置
// 2.超时时间
// 3.请求拦截器/响应拦截器

const request = axios.create({
  baseURL: 'http://geek.itheima.net/v1_0',
  timeout: 5000
})

// 添加请求拦截器
// 在请求发送之前  做拦截 插入一些自定义的配置[参数的处理]
request.interceptors.request.use((config)=> {
    //操作这个config 注入token数据
    //1.获取token
    //2.按照你好后端的格式要求做token拼接
    const token = getToken()
    if(token) {
        config.headers.Authorization = `Bearer ${token}`
    }
    return config
  }, (error)=> {
    return Promise.reject(error)
})

// 添加响应拦截器
// 在响应返回到客户端之前 做拦截 重点处理返回的数据
request.interceptors.response.use((response)=> {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response.data
  }, (error)=> {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    // 判断状态码是否是401  如果是401  表示token失效  跳转到登录页
    console.dir(error)
    if(error.response.status === 401) {
        //跳转到登录页
        router.navigate('/login',{replace:true})
        window.location.reload()
    }
    return Promise.reject(error)
})

export { request }

值得注意的有两点

1.添加了请求头Authorization这样方便每次发起请求后端去校验请求头中的Token是否正确,当然,这也是和后端约定的格式

2.interceptors中会判断状态码是否为401 ,这是和后端约定俗成的规则(不出意外的话)代表token失效或不存在 。也就是用户没有登录,或者登录过期,会强行跳转到登录页面重新登录

下面解决一个大家可能会有的疑问,既然Token已经存在了localStorage为何还要被Redux管理?

1. 避免频繁读取 localStorage(性能优化)​

  • localStorage 是同步 API,每次读取都会阻塞主线程,频繁读取可能影响性能。
  • Redux 存储在内存中,访问速度更快,适合高频访问的场景(如每次 API 请求都要带上 Token)。

示例对比

javascript 复制代码
// ❌ 每次调用 API 都从 localStorage 读取(性能差)
axios.get("/api/data", {
  headers: {
    Authorization: `Bearer ${localStorage.getItem("token")}`,
  },
});

// ✅ 从 Redux 中读取(内存操作,更快)
const token = useSelector((state) => state.auth.token);
axios.get("/api/data", {
  headers: { Authorization: `Bearer ${token}` },
});

2. 保持 UI 与状态的同步

  • localStorage 不会触发 React 组件更新,如果 Token 变化(如登录/登出),页面不会自动重新渲染。
  • Redux 状态变化会触发组件更新,确保 UI 及时响应 Token 的变化(如显示/隐藏登录按钮)。

示例场景

javascript 复制代码
// 登录成功后更新 Redux 和 localStorage
dispatch(loginSuccess(token)); // 更新 Redux
localStorage.setItem("token", token); // 持久化

// 组件中根据 Redux 状态显示不同 UI
const { token } = useSelector((state) => state.auth);
return token ? <Dashboard /> : <Login />;

3. 服务端渲染(SSR)兼容性

  • localStorage 是浏览器 API ,在 SSR(如 Next.js)环境下无法使用,会导致 ReferenceError
  • Redux 可以在服务端初始化状态,避免 SSR 报错。

解决方案

javascript 复制代码
// 在服务端渲染时,从请求头或 Cookie 初始化 Redux Token
const store = configureStore({
  preloadedState: { auth: { token: req.cookies.token } },
});

4. 方便 Token 的全局管理

  • Redux 提供统一的状态管理 ,方便在多个组件中共享 Token,避免手动传递 props
  • 支持中间件处理(如自动刷新 Token、拦截失效 Token)。

示例:Redux 中间件自动添加 Token

javascript 复制代码
axios.interceptors.request.use((config) => {
  const token = store.getState().auth.token;
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

5. 安全性增强

  • localStorage 易受 XSS 攻击,但 Token 仍需持久化存储(如用户刷新页面后保持登录)。

  • Redux 存储的 Token 仅在内存中 ,关闭页面后消失,配合 localStorage 实现:

    • 短期访问:从 Redux 读取(内存快,适合高频使用)。
    • 长期持久化 :从 localStorage 恢复(用户刷新页面后重新初始化 Redux)。

初始化 Redux 的 Token

javascript 复制代码
// 应用启动时从 localStorage 恢复 Token
const token = localStorage.getItem("token");
const store = configureStore({
  reducer: rootReducer,
  preloadedState: { auth: { token } },
});

结语

Token 管理 是前端开发中不可忽视的一环,Redux + localStorage 的组合方案既保证了数据的持久化,又优化了性能与状态同步。通过封装工具函数、统一管理 Token 存储与校验,我们可以减少重复代码,提高开发效率,同时增强应用的安全性和可维护性。

无论是小型项目还是企业级应用,这套模式都能灵活适配。希望本文的实践方案能帮助你快速搭建可靠的 Token 管理系统,让登录态管理变得简单高效!

相关推荐
无名之逆33 分钟前
[特殊字符]For Speed Enthusiasts: The Ultimate Evolution of Rust HTTP Engines
开发语言·前端·后端·网络协议·http·rust
巴巴_羊35 分钟前
前端八股HTTP和https大全套
前端·http·https
不写八个2 小时前
Express教程【002】:Express监听GET和POST请求
前端·javascript·express
pianmian17 小时前
3D Tiles高级样式设置与条件渲染(3)
linux·服务器·前端
资深前端之路7 小时前
vue+threeJs 绘制3D圆形
前端·javascript·vue.js
Nymph_Zhu8 小时前
vue3+element-plus el-date-picker日期、年份筛选设置本周、本月、近3年等快捷筛选
前端·vue.js·elementui
极客密码8 小时前
DeepSeek-R1-0528,官方的端午节特别献礼
前端·ai编程·deepseek
打小就很皮...8 小时前
npm、pnpm、yarn使用以及区别
前端·npm·yarn
FungLeo9 小时前
vue2 + webpack 老项目升级 node v22 + vite + vue2 实战全记录
前端·webpack·vue2·vie·webpack 升级 vite
西洼工作室9 小时前
使用原生前端技术封装一个组件
前端·js