如何用react-router-dom保护受保护路由内的嵌套路由?
解决嵌套路由跳转时JWT Token重新验证问题
问题原因
当前RequireAuth组件的useEffect依赖项为空数组,仅在组件首次挂载时执行Token验证。当在/dashboard/*嵌套路由间跳转时,RequireAuth组件不会卸载重挂载,因此不会触发新的验证逻辑。
解决方案
修改RequireAuth组件,让useEffect监听路由位置(location)和Token的变化,每次路由跳转或Token更新时重新验证:
修改后的RequireAuth.jsx
import { useState, useEffect } from 'react'; import { useLocation, Navigate, Outlet } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { selectCurrentToken, logOut } from './authSlice'; import { useVerifyTokenMutation } from './authApiSlice'; import FullScreenLoading from '../../components/general/FullScreenLoading'; function RequireAuth() { const [authenticated, setAuthenticated] = useState(null); const [isLoading, setIsLoading] = useState(true); const location = useLocation(); const [verifyToken] = useVerifyTokenMutation(); const token = useSelector(selectCurrentToken); const dispatch = useDispatch(); useEffect(() => { // 用于取消未完成的请求,避免内存泄漏 let isCancelled = false; const authenticateToken = async () => { setIsLoading(true); try { const response = await verifyToken({ token }).unwrap(); const { verified } = response.data; if (!isCancelled) { setAuthenticated(verified); } } catch (error) { const { verified } = error.data; dispatch(logOut()); if (!isCancelled) { setAuthenticated(verified); } } finally { if (!isCancelled) { setIsLoading(false); } } }; if (token) { authenticateToken(); } else { setIsLoading(false); setAuthenticated(false); } // 清理函数:标记请求已取消 return () => { isCancelled = true; }; }, [token, location, dispatch, verifyToken]); // 添加token和location到依赖数组 if (isLoading === true) { return <FullScreenLoading />; } return ( authenticated && !isLoading ? <Outlet /> : <Navigate to="/" state={{ from: location }} replace /> ); } export default RequireAuth;
关键修改点
- 依赖数组更新:将
token和location加入useEffect的依赖项,确保路由跳转(location变化)或Token变更时重新执行验证。 - 请求清理:添加
isCancelled标志,在组件卸载或重新触发effect时取消未完成的请求,避免内存泄漏和状态更新错误。 - 加载状态重置:每次验证前重置
isLoading为true,保证嵌套路由跳转时也能显示加载状态(可根据需求调整)。
额外优化建议
如果每次路由跳转都调用验证接口过于频繁,可以考虑:
- 给验证结果添加有效期,比如缓存验证状态5分钟,有效期内不重复请求。
- 仅在Token发生变化或路由跳转到特定敏感路径时才重新验证。
内容的提问来源于stack exchange,提问作者Jack Collins
相关产品推荐
相关产品推荐

