ReactJS中阻止用户手动修改浏览器URL进行路由访问
解决React路由中用户篡改LocalStorage角色访问管理员路由的问题
核心思路
前端不能完全信任客户端存储(比如localStorage)的权限信息,必须结合后端接口实时验证用户真实权限,同时优化权限校验逻辑的安全性和用户体验。
具体实现方案
1. 改造AdminAuth组件,加入后端权限验证
修改权限校验逻辑,不再仅依赖localStorage,而是调用后端接口确认用户的真实角色:
import React, { useState, useEffect } from "react"; import { Navigate } from "react-router-dom"; import { isAutheticated } from "../auth"; import { checkAdminPermission } from "../api/auth"; // 后端提供的权限验证接口 export const AdminAuth = ({ children, redirectTo }) => { const [isLoading, setIsLoading] = useState(true); const [isValidAdmin, setIsValidAdmin] = useState(false); const [errorMsg, setErrorMsg] = useState(""); useEffect(() => { const verifyAdminPermission = async () => { try { const authData = isAutheticated(); // 无基础认证信息直接判定无权限 if (!authData?.token) { setErrorMsg("请先登录"); setIsValidAdmin(false); return; } // 调用后端接口验证用户真实角色 const response = await checkAdminPermission(authData.token); if (response.data.isAdmin) { setIsValidAdmin(true); } else { setErrorMsg("无管理员访问权限"); setIsValidAdmin(false); } } catch (err) { setErrorMsg("权限验证失败,请重新登录"); setIsValidAdmin(false); } finally { setIsLoading(false); } }; verifyAdminPermission(); }, []); // 加载状态显示过渡提示,避免页面闪烁 if (isLoading) { return <div>权限验证中...</div>; } // 验证不通过时提示错误并跳转 if (!isValidAdmin) { alert(errorMsg); // 也可替换为项目内的自定义错误提示组件 return <Navigate to={redirectTo} replace />; } return children; };
2. 使用HTTP-only Cookie存储会话信息
将用户的会话Token存入HTTP-only Cookie,而非localStorage。这种Cookie无法被客户端JavaScript读取或修改,能从根源上避免用户篡改会话相关信息,后端接口直接从Cookie中获取Token进行权限校验。
3. 统一管理员路由的权限隔离
把所有管理员专属路由统一嵌套在一个路由组下,批量应用AdminAuth组件,减少重复配置:
const router = createBrowserRouter([ { path: "/", element: <App />, }, { path: "/main", element: ( <AdminAuth redirectTo="/profile"> <Main /> </AdminAuth> ), // 管理员子路由自动继承父级权限校验 children: [ { path: "/main/dashboard", element: <Dashboard /> }, { path: "/main/settings", element: <Settings /> }, ], }, ]);
4. 全局监听路由变化,二次校验
在App组件中监听路由变化,对管理员路由进行二次验证,防止用户直接修改URL跳转:
import { useLocation, useNavigate } from "react-router-dom"; function App() { const location = useLocation(); const navigate = useNavigate(); useEffect(() => { // 检测到访问管理员路由时触发校验 if (location.pathname.startsWith("/main")) { const authData = isAutheticated(); if (!authData?.token) { alert("请先登录"); navigate("/profile", { replace: true }); } // 可再次调用后端验证接口强化校验 } }, [location, navigate]); return ( // 你的App组件内容 ); }
关键注意事项
- 前端权限校验仅作为用户体验优化手段,核心权限控制必须依赖后端,所有敏感接口都要在后端层面校验用户权限。
- 永远不要信任客户端传递的任何权限信息,必须通过后端接口确认用户的真实身份与权限。
- 避免将敏感权限信息(如角色)暴露在客户端可修改的存储中,尽量通过后端接口实时获取。
内容的提问来源于stack exchange,提问作者user21103751
相关产品推荐
相关产品推荐

