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

如何用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;

关键修改点

  1. 依赖数组更新:将token和location加入useEffect的依赖项,确保路由跳转(location变化)或Token变更时重新执行验证。
  2. 请求清理:添加isCancelled标志,在组件卸载或重新触发effect时取消未完成的请求,避免内存泄漏和状态更新错误。
  3. 加载状态重置:每次验证前重置isLoading为true,保证嵌套路由跳转时也能显示加载状态(可根据需求调整)。

额外优化建议

如果每次路由跳转都调用验证接口过于频繁,可以考虑:

  • 给验证结果添加有效期,比如缓存验证状态5分钟,有效期内不重复请求。
  • 仅在Token发生变化或路由跳转到特定敏感路径时才重新验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:16:07