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

React受保护路由Token验证通过后无法跳转至Admin首页求助

React受保护路由验证通过后仍重定向至登录页问题

Token验证功能可正常检测有效性,但验证通过后仍被重定向至Login页面,无法进入预期的Admin首页。尝试在ProtectedRoute组件中使用<Outlet/>未生效,控制台显示Token验证完全正常,怀疑App.js中的路由配置存在问题,相关代码如下:


ProtectedRoute.js

import { Navigate } from 'react-router-dom';
import Cookies from 'js-cookie';
import { checkToken } from './auth';
import Admin from '../pages/Admin-page/Admin';
import { useState, useEffect } from 'react';

const ProtectedRoute = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [isValid, setIsValid] = useState(false);

  useEffect(() => {
    const verifyToken = async () => {
      try {
        const valid = await checkToken(); 
        console.log('Token valid:', valid); // Debugging

        setIsValid(valid);
      } catch (error) {
        console.error('Error validating token:', error);
        setIsValid(false);
      } finally {
        setIsLoading(false);
      }
    };

    verifyToken();
  }, []);

  if (isLoading) {
    return <div>Loading...</div>; 
  }
  console.log('Token isvalid:', isValid); // Debugging

  return isValid ? <Admin /> : <Navigate to="/login" replace />;
};

export default ProtectedRoute;

App.js

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './authentications/Login';
import Users from './pages/Side-menu/Users';
import Hours from './pages/Side-menu/Hours';
import Tenants from './pages/Side-menu/Tenants';
import ResetPassword from './authentications/ResetPassword';
import NewPassword from './authentications/NewPassword';
import ProtectedRoute from './authentications/ProtectedRoute';
import PostContent from './pages/Admin-page/PostContent';
import Admin from './pages/Admin-page/Admin';
import Home from './pages/Side-menu/Home';
import Signup from './authentications/Signup';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<Signup />} />
        <Route path="/forgotpassword" element={<ResetPassword />} />
        <Route path="/newpassword" element={<NewPassword />} />

        {/* Protected routes */}
        <Route
          path="/"
          element={
            <ProtectedRoute>
              <Admin />
            </ProtectedRoute>
          }
        >
          <Route path="admin/posts" element={<PostContent />} />
          <Route path="admin/users" element={<Users />} />
          <Route path="admin/hours" element={<Hours />} />
          <Route path="admin/tenants" element={<Tenants />} />
        </Route>
      </Routes>
    </Router>
  );
}

export default App;

Login.js

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslate } from '@tolgee/react';
import { LanguageSelect } from '../LanguageSelect';
import { checkToken } from './auth'; 
import axios from 'axios'; 
import Cookies from 'js-cookie'; 

function Login() {
  const [formData, setFormData] = useState({
    email: '',
    password: '',
  });
  const [errors, setErrors] = useState({ password: '' });
  const navigate = useNavigate();
  const { t } = useTranslate();

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  const validatePassword = (password) => {
    const regex = /^(?=.*[A-Z])(?=.*\d)[A-Za-z\d@#$%^&+=!]{8,}$/; // Updated regex
    return regex.test(password);
  };

  const handleLogin = async (e) => {
    e.preventDefault();

    if (!validatePassword(formData.password)) {
      setErrors({
        password:
          'Password must be at least 8 characters long, contain at least one uppercase letter and one number.',
      });
      return;
    }

    try {
      const response = await axios.post(
        'https://MYWEBSITE/api/v1/users/login',
        {
          email: formData.email,
          password: formData.password,
        },
        {
          headers: {
            'Content-Type': 'application/json',
          },
          withCredentials: true, // Added withCredentials setting
        }
      );

      if (response.status === 200) {
        console.log('Login successful.');
        setFormData({
          email: '',
          password: '',
        });
        
        const isValidToken = await checkToken();
        if (isValidToken) {
          console.log('Token is valid, navigating to homepage.');
          navigate('/'); // Redirect after successful login
        } else {
          console.error('Invalid token after login.');
        }
      } else {
        console.error('Error logging in:', response.statusText);
      }
    } catch (error) {
      console.error('Axios error:', error);
    }
  };

  return (
    {/* 组件渲染内容未在代码中提供 */}
  );
}

export default Login;

auth.js

import axios from 'axios';

export const checkToken = async () => {
  try {
    const response = await axios.get(
      'https://MYWEBSITE/api/v1/users/checkToken',
      {
        headers: {
          'Content-Type': 'application/json',
        },
        withCredentials: true, 
      }
    );

    return response.data.status === 'success';
  } catch (error) {
    if (error.response) {
      console.error('Server error:', error.response.data);
      return false;
    } else if (error.request) {
      console.error('Network error:', error.request);
      return false;
    } else {
      console.error('Request error:', error.message);
      return false;
    }
  }
};

问题根源与修复方案

1. ProtectedRoute未正确处理嵌套路由

当前ProtectedRoute直接返回<Admin/>,既忽略了传入的子组件,也未使用<Outlet/>渲染嵌套路由,导致路由结构失效。

修改后的ProtectedRoute.js

import { Navigate, Outlet } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { checkToken } from './auth';

const ProtectedRoute = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [isValid, setIsValid] = useState(false);

  useEffect(() => {
    const verifyToken = async () => {
      try {
        const valid = await checkToken(); 
        console.log('Token valid:', valid);
        setIsValid(valid);
      } catch (error) {
        console.error('Error validating token:', error);
        setIsValid(false);
      } finally {
        setIsLoading(false);
      }
    };

    verifyToken();
  }, []);

  if (isLoading) {
    return <div>Loading...</div>; 
  }

  // 验证通过时渲染嵌套路由的Outlet,否则重定向到登录页
  return isValid ? <Outlet /> : <Navigate to="/login" replace />;
};

2. App.js路由配置错误

原配置将ProtectedRoute与Admin组件混合使用,未正确建立父-子路由关系。需调整为用ProtectedRoute作为路由保护层,Admin作为父组件承载子路由。

修改后的App.js

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './authentications/Login';
import Users from './pages/Side-menu/Users';
import Hours from './pages/Side-menu/Hours';
import Tenants from './pages/Side-menu/Tenants';
import ResetPassword from './authentications/ResetPassword';
import NewPassword from './authentications/NewPassword';
import ProtectedRoute from './authentications/ProtectedRoute';
import PostContent from './pages/Admin-page/PostContent';
import Admin from './pages/Admin-page/Admin';
import Home from './pages/Side-menu/Home';
import Signup from './authentications/Signup';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<Signup />} />
        <Route path="/forgotpassword" element={<ResetPassword />} />
        <Route path="/newpassword" element={<NewPassword />} />

        {/* 受保护路由组:ProtectedRoute作为统一验证层 */}
        <Route element={<ProtectedRoute />}>
          {/* 默认路由指向Admin首页 */}
          <Route path="/" element={<Admin />} />
          {/* 嵌套子路由:若Admin组件内部包含<Outlet/>,可直接嵌套 */}
          <Route path="admin/posts" element={<Admin><PostContent /></Admin>} />
          <Route path="admin/users" element={<Admin><Users /></Admin>} />
          <Route path="admin/hours" element={<Admin><Hours /></Admin>} />
          <Route path="admin/tenants" element={<Admin><Tenants /></Admin>} />
        </Route>
      </Routes>
    </Router>
  );
}

export default App;

若Admin组件内部已集成<Outlet/>用于渲染子内容,可进一步简化路由配置:

<Route element={<ProtectedRoute />}>
  <Route path="/" element={<Admin />}>
    <Route path="admin/posts" element={<PostContent />} />
    <Route path="admin/users" element={<Users />} />
    <Route path="admin/hours" element={<Hours />} />
    <Route path="admin/tenants" element={<Tenants />} />
  </Route>
</Route>

3. 额外注意事项

  • 确保ProtectedRoute组件导入了useState和useEffect,原代码缺失该导入会导致组件报错。
  • 登录后跳转的/路径现在会匹配受保护路由的默认规则,直接渲染Admin组件。

内容的提问来源于stack exchange,提问作者Diana Petrovčíková

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:27:02