React Redux中跨页面复用登录JWT Token并在请求头携带的方法
React+Redux项目全局复用JWT Token并自动携带鉴权的实现流程
1. 登录成功后持久化存储Token
登录接口拿到后端返回的JWT后,需要同时存储到两个位置,保证全项目可复用且刷新不丢失:
- Redux全局状态:所有页面、组件可以直接读取登录态、Token做权限判断
- localStorage/sessionStorage:做持久化,避免页面刷新后Redux状态重置导致登录态失效
参考代码:
// 登录action逻辑示例 function login(loginForm) { return async (dispatch) => { try { const res = await axios.post('http://localhost:9091/login', loginForm) const token = res.data.token // 按接口实际返回的Token字段取值 // 持久化到本地存储 localStorage.setItem('jwt_token', token) // 同步到Redux全局状态 dispatch({ type: 'SET_LOGIN_TOKEN', payload: token }) // 登录成功后的跳转逻辑 } catch (err) { // 登录失败提示逻辑 } } }
对应的用户状态reducer配置:
// src/store/reducers/userReducer.js const initialState = { // 初始化时直接从本地存储读,保证刷新后初始状态带Token token: localStorage.getItem('jwt_token') || '', // 其他用户信息字段按需添加 } export default function userReducer(state = initialState, action) { switch(action.type) { case 'SET_LOGIN_TOKEN': return { ...state, token: action.payload } case 'CLEAR_LOGIN_STATE': // 退出登录、鉴权失败时清空存储 localStorage.removeItem('jwt_token') return { ...state, token: '' } default: return state } }
2. 封装带统一拦截器的Axios实例
不要在每个action文件中直接引入原生axios,单独抽离公共请求工具,通过请求拦截器统一给所有需要鉴权的接口加请求头,避免每个接口重复写加Token的逻辑。
新建src/utils/request.js文件:
import axios from 'axios' import store from '../store' // 引入项目的Redux store实例 // 创建统一axios实例 const service = axios.create({ baseURL: 'http://localhost:9091', // 接口统一前缀,后续写接口不用重复写域名 timeout: 10000 }) // 请求拦截器:发请求前自动注入Token service.interceptors.request.use( config => { const token = localStorage.getItem('jwt_token') if (token) { // 头字段、格式按后端约定调整,通用格式为Bearer + Token config.headers['Authorization'] = `Bearer ${token}` } return config }, error => Promise.reject(error) ) // 响应拦截器:统一处理鉴权失败场景 service.interceptors.response.use( response => { return response.data // 直接返回接口data层,后续调用不用重复写res.data }, error => { // 401状态码代表Token无效、过期,直接清空登录态跳登录页 if (error.response?.status === 401) { store.dispatch({ type: 'CLEAR_LOGIN_STATE' }) window.location.href = '/login' } return Promise.reject(error) } ) export default service
3. 改造现有UPI接口请求
把原来upi action中引入的原生axios替换为封装好的请求实例,所有后续新增的需要鉴权的接口,都统一用这个实例发送,会自动在请求头携带Token。
改造后的upi action代码:
// 替换原来的原生axios引入 import request from '../utils/request'; export const upiAction = { upi, }; function upi(user) { return (dispatch) => { var data = { upiId: user.upiId, accountNumber: user.accountNumber, }; request // 替换为封装好的实例,自动携带Token .post('/upiidcreation', data) // 配置了baseURL后直接写接口路径即可 .then((res) => { console.log("res", res); alert(JSON.stringify(res.responseDesc)); }) .catch(err => { dispatch(setUserUpiError(err, true)); alert("Please Check With details"); }); }; } export function setUserUpi(showError) { return { type: 'SET_UPI_SUCCESS', showError: showError, }; } export function setUserUpiError(error, showError) { return { type: 'SET_UPI_ERROR', error: error, showError: showError, }; }
注意事项
- 请求头的Token格式要和后端约定一致,如果后端要求自定义头字段(比如
X-Token)、不需要Bearer前缀,直接修改请求拦截器里的headers配置即可。 - 对安全性要求高的场景,可以把Token存在sessionStorage,关闭浏览器自动清除,比localStorage风险更低。
- 退出登录时记得手动调用
CLEAR_LOGIN_STATE的action,清空本地存储和Redux里的Token。
内容的提问来源于stack exchange,提问作者Karthiga
相关产品推荐
相关产品推荐

