React Router未配置受保护路由 未登录可访问内部页求助
问题根因
- 仅根路径
/配置了登录态判断,/dashboard、/history等所有内部页面路由完全没加访问拦截,路由匹配到就直接渲染组件,直接输地址当然能进。 - 登录状态只存在组件内存state里,页面一刷新state就重置回初始空对象,就算加了路由拦截,刷新后也会异常跳回登录页。
- 现有代码里
/employee路径重复绑定了两个组件,后写的Addemploye会覆盖前面的Employee组件路由,属于附带bug,需要一起修复。
修复方案
第一步:封装通用权限路由组件
新建ProtectedRoute.jsx,统一处理拦截逻辑,不用每个路由重复写判断:
import { Navigate } from "react-router-dom"; function ProtectedRoute({ children }) { // 优先从本地存储取登录态,避免刷新丢失 const user = JSON.parse(localStorage.getItem("loginUser") || '{}'); // 未登录直接跳登录页 if (!user._id) { return <Navigate to="/login" replace />; } // 已登录正常渲染目标页面 return children; } export default ProtectedRoute;
第二步:修改登录逻辑,持久化登录态
修改Login.jsx的登录成功回调,把用户信息存入localStorage,保证刷新不丢状态:
const login = () => { axios.post("/login", user).then((res) => { alert(res.data.message); const loginUser = res.data.user; setusers(loginUser); // 持久化存储登录态 localStorage.setItem("loginUser", JSON.stringify(loginUser)); history.push("/dashboard") }); };
后续补退出登录逻辑时,记得调用localStorage.removeItem("loginUser")清除存储,再跳回登录页即可。
第三步:改造App.js路由配置
所有需要权限的页面用ProtectedRoute包裹,同时修复重复路由问题:
import "./App.css"; import { Routes, Route, Navigate } from "react-router-dom"; import Dashboard from "./Components/After Login/Dashboard/Dashboard"; import Task from "./Components/After Login/Task/Task"; import Employee from "./Components/After Login/Employee/Employee"; import History from "./Components/After Login/History/History"; import Notification from "./Components/After Login/Notification/Notification"; import Popup from "./Components/After Login/Task/Popup"; import Addemploye from "./Components/After Login/Employee/Addemploye"; import EmployeeCard from "./Components/After Login/Employee/EmployeeCard"; import Login from "./Components/Before Login/Login/Login"; import ProtectedRoute from "./ProtectedRoute"; import { useState, useEffect } from "react"; function App() { const [user, setusers] = useState({}); // 初始化时从本地存储同步登录态到state useEffect(() => { const savedUser = JSON.parse(localStorage.getItem("loginUser") || '{}'); if (savedUser._id) setusers(savedUser); }, []); return ( <Routes> {/* 根路径重定向逻辑 */} <Route path="/" element={ user?._id ? <Navigate to="/dashboard" replace /> : <Navigate to="/login" replace /> } /> {/* 登录页,已登录访问直接跳控制台 */} <Route path="/login" element={ user?._id ? <Navigate to="/dashboard" replace /> : <Login setusers={setusers} /> } /> {/* 以下为受保护路由,全部接入权限校验 */} <Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} /> <Route path="/task" element={<ProtectedRoute><Task /></ProtectedRoute>} /> <Route path="/createtask" element={<ProtectedRoute><Popup /></ProtectedRoute>} /> <Route path="/employee" element={<ProtectedRoute><Employee /></ProtectedRoute>} /> {/* 给新增员工页分配独立路径,解决路由重复覆盖问题 */} <Route path="/employee/add" element={<ProtectedRoute><Addemploye /></ProtectedRoute>} /> <Route path="/history" element={<ProtectedRoute><History /></ProtectedRoute>} /> <Route path="/notification" element={<ProtectedRoute><Notification /></ProtectedRoute>} /> <Route path="/employee/:id" element={<ProtectedRoute><EmployeeCard /></ProtectedRoute>} /> </Routes> ); } export default App;
补充说明
- 路由上的
replace属性用于替换路由栈历史,避免用户点浏览器返回键出现异常跳回登录页的问题。 - 如果后续要加角色权限控制(比如普通员工不能访问员工管理页),直接在
ProtectedRoute组件里加角色判断逻辑即可,不需要修改每个页面的代码。 - 本地存储存用户信息仅为前端简易方案,生产环境建议结合token做鉴权,接口请求统一携带token,后端校验有效期,前端拿到401状态码自动清除登录态跳回登录页。
内容的提问来源于stack exchange,提问作者NOTkryp
相关产品推荐
相关产品推荐

