react路由守卫、权限控制实现

React 本身没有像 Vue (beforeEach) 那样内置的路由守卫 ,一般都是通过 React Router + 登录状态 + 权限控制 + 高阶组件(HOC) / 自定义组件 / Hook 来实现。

React 企业项目(后台管理、ERP、OA、CMS)一般都会实现四层权限:

复制代码
登录认证(Auth)
      ↓
路由权限(Route Guard)
      ↓
菜单权限(Menu Permission)
      ↓
按钮权限(Button Permission)

下面按照企业项目的方式完整讲解。


一、React 路由守卫是什么?

作用:

用户访问页面之前,先判断有没有权限。

例如:

复制代码
未登录

访问

/login
    √

/home
    ×
跳到 login

/user
    ×

/system
    ×

登录以后

复制代码
admin

/home
√

/system
√

/user
√

普通用户

复制代码
/home
√

/system
×

/user
√

所以路由守卫主要干三件事:

复制代码
① 是否登录
② 是否有角色权限
③ 是否有页面权限

二、React Router v6 路由

例如:

复制代码
import { BrowserRouter, Routes, Route } from "react-router-dom";

<BrowserRouter>
    <Routes>
        <Route path="/login" element={<Login />} />

        <Route path="/" element={<Layout />}>
            <Route path="home" element={<Home />} />
            <Route path="user" element={<User />} />
            <Route path="system" element={<System />} />
        </Route>
    </Routes>
</BrowserRouter>

但是这里任何人都能访问。

需要加守卫。


三、第一层:登录守卫

创建

复制代码
AuthRoute.tsx

import { Navigate } from "react-router-dom";

export default function AuthRoute({ children }) {

    const token = localStorage.getItem("token");

    if (!token) {
        return <Navigate to="/login" replace />;
    }

    return children;
}

然后包裹页面。

复制代码
<Route
    path="/"
    element={
        <AuthRoute>
            <Layout />
        </AuthRoute>
    }
/>

流程:

复制代码
访问

↓

有没有token

↓

没有

↓

Navigate("/login")

↓

有

↓

继续访问

四、token 一般存哪里?

企业里一般:

复制代码
登录

↓

接口返回

{
    token:"xxxxx"
}

保存

复制代码
localStorage.setItem("token", token);

退出登录

复制代码
localStorage.removeItem("token");

或者

Redux

复制代码
store.user.token

或者

Context

复制代码
UserContext

五、第二层:角色权限

后台一般返回:

复制代码
{
    "username":"admin",
    "role":"admin"
}

或者

复制代码
{
    "roles":[
        "admin",
        "editor"
    ]
}

定义路由:

复制代码
const routes = [
    {
        path:"/home",
        element:<Home/>
    },
    {
        path:"/system",
        roles:["admin"],
        element:<System/>
    },
    {
        path:"/user",
        roles:["admin","editor"],
        element:<User/>
    }
]

守卫:

复制代码
const role = "editor";

if(route.roles){

    if(!route.roles.includes(role)){
        return <Navigate to="/403"/>
    }

}

效果:

复制代码
admin

home
√

system
√

user
√

editor

home
√

system
×

user
√

六、第三层:菜单权限

后台返回:

复制代码
[
    "/home",
    "/user"
]

说明:

用户只能看到

复制代码
首页
用户管理

菜单配置:

复制代码
const menus = [
    {
        path:"/home",
        title:"首页"
    },
    {
        path:"/user",
        title:"用户"
    },
    {
        path:"/system",
        title:"系统设置"
    }
]

过滤:

复制代码
const permission = ["/home","/user"];

const menu = menus.filter(item=>{
    return permission.includes(item.path);
})

最终:

复制代码
首页
用户管理

系统设置不会显示。


七、第四层:按钮权限

后台返回:

复制代码
[
    "user:add",
    "user:delete",
    "user:update"
]

页面:

复制代码
<button>新增</button>

<button>删除</button>

<button>修改</button>

可以封装:

复制代码
function Permission({ code, children }) {

    const buttons = [
        "user:add",
        "user:update"
    ];

    if(buttons.includes(code)){
        return children;
    }

    return null;
}

使用:

复制代码
<Permission code="user:add">
    <Button>新增</Button>
</Permission>

<Permission code="user:delete">
    <Button>删除</Button>
</Permission>

结果:

复制代码
新增 √

删除 ×

八、动态路由权限(企业最常见)

很多后台不会把所有路由写死。

登录后:

复制代码
login

↓

token

↓

获取用户信息

↓

获取权限

↓

后台返回路由

↓

动态生成React Router

例如后台返回:

复制代码
[
    {
        "path":"/home",
        "component":"Home"
    },
    {
        "path":"/user",
        "component":"User"
    }
]

前端映射:

复制代码
const componentMap = {
    Home: Home,
    User: User,
    System: System
};

const routes = backendRoutes.map(item => ({
    path: item.path,
    element: React.createElement(componentMap[item.component])
}));

这样后台控制:

复制代码
哪些页面能访问

不用重新发版。


九、完整流程(企业项目)

复制代码
用户访问

↓

Route Guard

↓

有没有token?

↓

没有

↓

login

↓

登录

↓

token

↓

获取用户信息

↓

获取角色

↓

获取菜单权限

↓

获取按钮权限

↓

动态生成菜单

↓

动态生成路由

↓

进入首页

十、推荐项目目录结构

复制代码
src
│
├── router
│   ├── index.tsx          // 路由入口
│   ├── routes.ts          // 路由配置
│   ├── AuthRoute.tsx      // 登录守卫
│   ├── PermissionRoute.tsx// 权限守卫
│
├── layouts
│   └── Layout.tsx
│
├── pages
│   ├── Login
│   ├── Home
│   ├── User
│   └── System
│
├── store
│   └── user.ts            // token、角色、权限
│
├── hooks
│   └── usePermission.ts   // 权限 Hook
│
├── components
│   └── Permission.tsx     // 按钮权限组件
│
└── utils
    └── auth.ts            // token 工具

十一、企业级最佳实践(React Router v6 + Redux)

对于使用 React Router v6 + Redux(或 Zustand) 的中大型项目,推荐采用以下职责划分:

模块 职责 数据来源
登录认证 校验 Token 是否存在、是否过期 localStorage + Redux
路由守卫 拦截未登录用户、校验页面访问权限 Redux 中的用户信息和权限
菜单权限 根据后端返回的菜单列表动态渲染侧边栏 后端菜单接口
动态路由 根据后端返回的路由配置生成可访问路由 路由配置接口
按钮权限 控制按钮、操作入口是否显示或禁用 后端权限码(如 user:add
权限 Hook 封装权限判断逻辑(如 usePermission Redux/Zustand
Permission 组件 在 JSX 中优雅地控制权限显示 权限 Hook

这种分层方式具有以下优点:

  • 职责清晰:认证、路由、菜单、按钮权限互不耦合。

  • 便于扩展:新增角色或权限类型时,只需调整权限配置和判断逻辑。

  • 符合企业后台实践:适用于 React + Ant Design、React + Material UI 等常见后台管理系统,也便于与 RBAC(基于角色的访问控制)模型结合。

  • 支持动态权限:能够结合后端返回的数据,实现菜单、路由和按钮权限的统一管理。

如果你正在准备前端面试,这套实现(登录认证 + 路由守卫 + 动态路由 + 菜单权限 + 按钮权限 + RBAC)基本覆盖了 React 中后台项目关于权限控制的高频考点。