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

如何使用React Router Dom V6实现不同用户角色的路由访问限制

如何使用React Router Dom V6实现不同用户角色的路由访问限制

我来帮你搞定这个路由权限的问题~你现在的核心问题是:虽然登录后能跳转到对应角色的页面,但手动修改地址栏就能跨角色访问,这是因为你当前的路由写法只是把不同角色的路由分开成独立的Routes组件,并没有做任何权限校验,React Router会直接匹配到对应的路由并渲染。

咱们可以通过自定义受保护路由组件的方式来解决这个问题,具体步骤如下:

第一步:创建访问拒绝页面

先做一个简单的AccessDenied页面,用来提示用户没有权限:

// AccessDenied.jsx
const AccessDenied = () => {
  return (
    <div style={{ textAlign: 'center', marginTop: '50px' }}>
      <h1>访问被拒绝</h1>
      <p>您没有权限访问该页面,请确认您的用户角色</p>
    </div>
  );
};

export default AccessDenied;

第二步:完善登录逻辑,存储用户角色

首先要确保登录成功后,把用户的角色信息存在本地(比如localStorage,如果用了Redux/Context也可以存在状态里),这样后续路由校验才能拿到角色:

// 登录页面的登录逻辑修改
if (res.data.data.user?.role?.name.toLowerCase() === "vendor") {
  // 把用户信息存在localStorage
  localStorage.setItem('user', JSON.stringify(res.data.data.user));
  navigate("/dashboard");             
} else {
  localStorage.setItem('user', JSON.stringify(res.data.data.user));
  navigate("/buyer-dashboard");
}

第三步:编写角色校验的自定义路由组件

创建一个RequireRole组件,用来检查当前用户的角色是否符合路由的访问要求,不符合就跳转到访问拒绝页面:

// RequireRole.jsx
import { Navigate, Outlet } from 'react-router-dom';

const RequireRole = ({ allowedRoles }) => {
  // 从localStorage获取用户信息(如果用状态管理就从状态里取)
  const user = JSON.parse(localStorage.getItem('user'));
  const userRole = user?.role?.name.toLowerCase();

  // 如果用户未登录,直接跳转到登录页
  if (!user) {
    return <Navigate to="/" replace />;
  }

  // 如果用户角色不在允许的列表里,跳转到访问拒绝页
  if (!allowedRoles.includes(userRole)) {
    return <Navigate to="/access-denied" replace />;
  }

  // 权限校验通过,渲染嵌套的子路由
  return <Outlet />;
};

export default RequireRole;

第四步:重构App.jsx的路由结构

把所有路由整合到一个Routes组件里,用RequireRole来包裹对应角色的路由,实现权限控制:

// App.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import RequireRole from './RequireRole';
import AccessDenied from './AccessDenied';
// 导入你的其他组件
import Login from './Login';
import SignUp from './SignUp';
import Confirmation from './Confirmation';
import ForgetPassword from './ForgetPassword';
import SetPassword from './SetPassword';
import Dashboard from './Dashboard';
import Other from './Other';
import VendorDashboard from './VendorDashboard';
import Items from './Items';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        {/* 公共路由:所有用户(包括未登录)都能访问 */}
        <Route index element={<Login />} />
        <Route path='/signup' element={<SignUp />} />
        <Route path='/email-confirmation' element={<Confirmation />} />
        <Route path='/forget-password' element={<ForgetPassword />} />
        <Route path='/set-password/:email' element={<SetPassword />} />
        <Route path='/access-denied' element={<AccessDenied />} />

        {/* Vendor专属路由:只有vendor角色能访问 */}
        <Route element={<RequireRole allowedRoles={['vendor']} />}>
          <Route path="/dashboard" element={<VendorDashboard />} />
          <Route path="/items" element={<Items />} />
        </Route>

        {/* Buyer专属路由:只有buyer角色能访问 */}
        <Route element={<RequireRole allowedRoles={['buyer']} />}>
          <Route path="/buyer-dashboard" element={<Dashboard />} />
          <Route path="/other" element={<Other />} />
        </Route>

        {/* 404页面:匹配所有未定义的路由 */}
        <Route path='*' element={<div style={{ textAlign: 'center', marginTop: '50px' }}>404 页面不存在</div>} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

为什么这样改能解决问题?

你之前的写法是把三个独立的Routes组件放在BrowserRouter里,React Router V6会依次匹配这些Routes里的路由,完全不做权限校验。现在的写法是把所有路由统一管理,用Outlet嵌套受保护的子路由,只有通过RequireRole的角色校验,才会渲染对应的子页面,否则直接跳转到访问拒绝或登录页。

另外提个小建议:如果你的应用比较复杂,建议用Context或者Redux来管理用户状态,比localStorage更安全(避免XSS攻击),退出登录的时候记得清除用户信息哦~

备注:内容来源于stack exchange,提问作者InteleJay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 12:38:01