React.js中Cookie过期未自动登出问题:路由切换无拦截
我有一个privateroute.js文件,用于路由权限和token状态校验,功能基本正常,但存在一个问题:即使Cookie过期,导航到受保护路由时不会自动登出,只有刷新页面才会跳转到登录页。
示例场景
即使内存中已无有效Cookie,从localhost:3000导航到localhost:3000/dashboard/analytics仍会被允许访问,但刷新页面后会立即跳转到login页面。
原代码
PrivateRoute.js
const ProtectedRoute = ({ component: Component, ...rest }) => { const cookies = new Cookies(); const [authenticated, setAuthenticated] = useState(null); const navigate = useNavigate(); const user = cookies.get("authToken"); const _id=cookies.get("xyz"); useEffect(async() => { let as=null; const cookies = new Cookies(); if (user) { const config = { headers: { "Content-Type": "application/json", 'Authorization':`Bearer ${user}`, }, }; try{ const {data}=await axios.post( `/api/auth/Veri`, { _id }, config ); if(data.email){ setAuthenticated(true); } else{ navigate("authentication/card/login"); } } catch(error){ ast=false; navigate("authentication/card/login"); } } else { ast=false; setAuthenticated(false); navigate("authentication/card/login"); } } , []); useEffect(()=>{ if(authenticated==false){ navigate("authentication/card/login"); } }, []); return ( authenticated ? <Outlet/> : null ) } export default ProtectedRoute;
Layout.js(路由文件)
<Route element={<PrivateRoutes/>}> <Route element={<MainLayout />}> {/*Dashboard*/} <Route path="/" element={<Dashboard />} /> <Route path="dashboard/analytics" element={<Analytics />} /> <Route path="dashboard/crm" element={<Crm />} /> <Route path="dashboard/saas" element={<Saas />} /> <Route path="dashboard/e-commerce" element={<Ecommerce />} /> </Route> </Route>
问题原因
- Cookie读取时机错误:
user和_id仅在组件初始化时读取一次,后续路由导航时不会获取最新的Cookie状态; - useEffect依赖缺失:第一个
useEffect依赖数组为空,仅在组件挂载时执行一次校验,路由切换时不会重新触发; - 状态变化未监听:第二个
useEffect依赖为空,authenticated状态变化时无法触发导航逻辑; - 异步回调不规范:直接将
async作为useEffect回调函数,可能导致内存泄漏或逻辑异常。
修复方案
修改ProtectedRoute.js,确保每次路由切换时重新校验权限,并正确响应状态变化:
import { useState, useEffect } from 'react'; import { useNavigate, useLocation, Outlet } from 'react-router-dom'; import Cookies from 'js-cookie'; import axios from 'axios'; const ProtectedRoute = () => { const [authenticated, setAuthenticated] = useState(null); const navigate = useNavigate(); const location = useLocation(); useEffect(() => { const validateAuth = async () => { // 每次校验都读取最新的Cookie const authToken = Cookies.get("authToken"); const userId = Cookies.get("xyz"); // 无Cookie直接标记未认证 if (!authToken || !userId) { setAuthenticated(false); return; } try { const config = { headers: { "Content-Type": "application/json", 'Authorization': `Bearer ${authToken}`, }, }; const { data } = await axios.post( `/api/auth/Veri`, { _id: userId }, config ); // 根据接口返回判断认证状态 if (data.email) { setAuthenticated(true); } else { setAuthenticated(false); } } catch (error) { // 请求失败直接标记未认证 setAuthenticated(false); } }; validateAuth(); }, [location.pathname, navigate]); // 路由变化时重新执行校验 // 监听认证状态变化,未认证时跳转登录页 useEffect(() => { if (authenticated === false) { navigate("authentication/card/login"); } }, [authenticated, navigate]); // 认证状态未确定时返回null,避免闪烁;认证通过则渲染子路由 return authenticated ? <Outlet /> : null; }; export default ProtectedRoute;
关键修改点
- 使用
useLocation监听路由路径变化,每次导航时重新执行权限校验; - 将Cookie读取逻辑放到校验函数内部,确保每次都获取最新的Cookie状态;
- 修复
async直接作为useEffect回调的问题,内部定义异步函数再调用; - 给两个
useEffect添加正确的依赖数组,确保状态变化和路由变化时触发相应逻辑; - 统一处理
authenticated状态,将导航逻辑集中到状态监听的useEffect中,避免逻辑分散。
内容的提问来源于stack exchange,提问作者COders Lime
相关产品推荐
相关产品推荐

