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

React JS中保护非登录注册页面及解决登录跳转异常问题

React 路由权限控制解决方案

你的问题核心在于同步判断认证状态无法跟上登录的异步流程,加上React Router v6的写法错误,导致登录后跳转时token还未存入localStorage,路由判断依然返回未认证。以下是可行的修复方案:

1. 先修正路由写法错误

React Router v6 已不再使用Component属性,所有路由组件都要通过element属性传入JSX:

// 错误写法
<Route path="/login" Component={Login}/>

// 正确写法
<Route path="/login" element={<Login />}/>

2. 用状态跟踪认证状态

localStorage的变化不会自动触发组件重渲染,所以需要用React状态来维护认证状态,确保状态更新时路由能重新判断:

import { useState, useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';

// 封装私有路由组件
const PrivateRoute = ({ children }) => {
  const [isLoading, setIsLoading] = useState(true);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    // 初始化时检查localStorage中的token
    const checkAuth = () => {
      const token = localStorage.getItem('JWTtoken');
      setIsAuthenticated(!!token);
      setIsLoading(false);
    };

    checkAuth();
    // 监听localStorage变化(处理多标签页登录同步)
    const handleStorageChange = (e) => {
      if (e.key === 'JWTtoken') {
        setIsAuthenticated(!!e.newValue);
      }
    };
    window.addEventListener('storage', handleStorageChange);
    return () => window.removeEventListener('storage', handleStorageChange);
  }, []);

  // 加载状态避免页面闪烁
  if (isLoading) {
    return <div>加载中...</div>; // 可替换为自定义加载组件
  }

  return isAuthenticated ? children : <Navigate to="/login" replace />;
};

function App() {
  return (
    <div className='bg'>
      <BrowserRouter>
        <Navi/>
        <Routes>
          {/* 公开路由 */}
          <Route path="/login" element={<Login />}/>
          <Route path="/signup" element={<Signup />}/>
          {/* 私有路由,需要认证才能访问 */}
          <Route path='/' element={<PrivateRoute><Home/></PrivateRoute>}/>
          <Route path='/profile' element={<PrivateRoute><UserProfile/></PrivateRoute>}/>
          <Route path='/dashboard' element={<PrivateRoute><UserDashboard/></PrivateRoute>}/>
          <Route path='/admindashboard' element={<PrivateRoute><AdminDashboard/></PrivateRoute>}/>
          <Route path='/transactionhistory' element={<PrivateRoute><TransactionHistory/></PrivateRoute>}/>
          <Route path='/about' element={<PrivateRoute><About/></PrivateRoute>}/>
          <Route path='/loans' element={<PrivateRoute><Loans/></PrivateRoute>}/>
          <Route path='/loan' element={<PrivateRoute><Loan/></PrivateRoute>}/>
          {/* 注意组件名不能有空格,路径建议用短横线分隔 */}
          <Route path='/loan-approval' element={<PrivateRoute><LoanApproval/></PrivateRoute>}/>
        </Routes>
      </BrowserRouter>
    </div>
  )
}

export default App

3. 确保登录流程正确

在Login组件中,必须先将token存入localStorage,再执行页面跳转,避免跳转时token还未写入:

// Login组件示例
import { useNavigate } from 'react-router-dom';

const Login = () => {
  const navigate = useNavigate();

  const handleLogin = async (credentials) => {
    try {
      // 发送登录请求
      const res = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials),
        headers: { 'Content-Type': 'application/json' }
      });
      const data = await res.json();
      // 先存token
      localStorage.setItem('JWTtoken', data.token);
      // 再跳转
      navigate('/');
    } catch (err) {
      console.error('登录失败:', err);
    }
  };

  return (
    // 登录表单
  );
};

关键说明

  • 私有路由组件PrivateRoute封装了认证逻辑,所有需要权限的页面都用它包裹,避免重复代码。
  • 加入加载状态是为了防止页面初始化时,还没检查完token就直接跳转到登录页,导致不必要的跳转。
  • 监听storage事件是为了处理多标签页登录的同步问题,比如在一个标签页登录后,其他标签页能自动更新认证状态。

内容的提问来源于stack exchange,提问作者HARI PRASATH V

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:13:21