news 2026/4/21 22:55:37

管理系统权限管理(菜单、页面、按钮)react+redux/vue3 pinia实现方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
管理系统权限管理(菜单、页面、按钮)react+redux/vue3 pinia实现方式

一、Vue3 + Pinia 权限控制示例

1️⃣ 权限点接口示例(后端返回)

{ "token": "xxx", "perms": [ "user:list", "user:add", "order:view" ] }

2️⃣ Pinia Store (stores/permission.ts)

import { defineStore } from 'pinia' interface UserData { id: string; name: string; role: string; } interface PermissionState { token: string userData: UserData | null perms: string[] } export const usePermissionStore = defineStore('permission', { state: (): PermissionState => ({ token: '', userData: null, perms: [] }), actions: { setToken(token: string) { this.token = token }, setUserData(user: UserData) { this.userData = user }, setPerms(perms: string[]) { this.perms = perms }, clear() { this.token = '' this.userData = null this.perms = [] }, // 根据 perms 过滤路由 filterRoutes(routes: any[]) { return routes.filter(route => { if (!route.meta?.perms) return true return route.meta.perms.some((p: string) => this.perms.includes(p)) }).map(route => { if (route.children) { route.children = this.filterRoutes(route.children) } return route }) }, // 菜单生成 generateMenus(routes: any[]) { return this.filterRoutes(routes) } } })

路由配置示例

export const asyncRoutes = [ { path: '/user', name: 'User', component: () => import('@/views/user/index.vue'), meta: { title: '用户管理', perms: ['user:list'] }, children: [ { path: 'add', name: 'UserAdd', component: () => import('@/views/user/add.vue'), meta: { title: '新增用户', perms: ['user:add'] } } ] }, { path: '/order', name: 'Order', component: () => import('@/views/order/index.vue'), meta: { title: '订单管理', perms: ['order:view'] } } ]

登录后调用

import { usePermissionStore } from '@/stores/permission' const permissionStore = usePermissionStore() const { token, userData, perms } = await api.login() permissionStore.setToken(token) permissionStore.setUserData(userData) permissionStore.setPerms(perms) // 生成菜单 const menuList = permissionStore.generateMenus(asyncRoutes)

按钮权限判断

<template> <button v-if="hasPerm('user:add')">新增用户</button> </template> <script setup lang="ts"> import { usePermissionStore } from '@/stores/permission' const permissionStore = usePermissionStore() function hasPerm(code: string) { return permissionStore.perms.includes(code) } </script>

二、React + Redux Toolkit 权限控制示例

Redux Slice (store/permissionSlice.ts)

import { createSlice, PayloadAction } from '@reduxjs/toolkit' interface UserData { id: string name: string role: string } interface PermissionState { token: string userData: UserData | null perms: string[] } const initialState: PermissionState = { token: '', userData: null, perms: [] } const permissionSlice = createSlice({ name: 'permission', initialState, reducers: { setToken: (state, action: PayloadAction<string>) => { state.token = action.payload }, setUserData: (state, action: PayloadAction<UserData>) => { state.userData = action.payload }, setPerms: (state, action: PayloadAction<string[]>) => { state.perms = action.payload }, clear: (state) => { state.token = '' state.userData = null state.perms = [] } } }) export const { setToken, setUserData, setPerms, clear } = permissionSlice.actions export default permissionSlice.reducer

Redux Store (store/index.ts)

import { configureStore } from '@reduxjs/toolkit' import permissionReducer from './permissionSlice' export const store = configureStore({ reducer: { permission: permissionReducer } }) export type RootState = ReturnType<typeof store.getState> export type AppDispatch = typeof store.dispatch

路由配置示例

import { lazy } from 'react' export const asyncRoutes = [ { path: '/user', element: lazy(() => import('@/pages/User')), meta: { title: '用户管理', perms: ['user:list'] }, children: [ { path: 'add', element: lazy(() => import('@/pages/UserAdd')), meta: { title: '新增用户', perms: ['user:add'] } } ] }, { path: '/order', element: lazy(() => import('@/pages/Order')), meta: { title: '订单管理', perms: ['order:view'] } } ]

登录后过滤路由

import { useSelector } from 'react-redux' import { RootState } from './store' const perms = useSelector((state: RootState) => state.permission.perms) function filterRoutes(routes: any[], perms: string[]) { return routes.filter(route => { if (!route.meta?.perms) return true return route.meta.perms.some((p: string) => perms.includes(p)) }).map(route => { if (route.children) route.children = filterRoutes(route.children, perms) return route }) } const allowedRoutes = filterRoutes(asyncRoutes, perms)

菜单渲染 & 按钮权限

// 菜单渲染 <Menu> {allowedRoutes.map(r => ( <Menu.Item key={r.path}>{r.meta.title}</Menu.Item> ))} </Menu> // 按钮权限 {perms.includes('user:add') && <Button>新增用户</Button>}

核心思路(Vue / React 通用)

  1. 后端只返回 perms 数组 → 前端根据它控制 UI
  2. 前端菜单 / 路由根据 perms 过滤
  3. 按钮或页面模块用 perms.includes(…) 控制显示
  4. 后端接口 仍然要校验 perms → 真正的安全保障

菜单写死在前端,通过权限点 v-if 显示/隐藏(大厂常用)

流程:

  1. 菜单是前端写死的(存 routes.ts)
  2. 用户登录,后台只返回权限点(字符串数组,如 [‘user:add’, ‘user:delete’])
  3. 前端根据权限点过滤导航栏、路由
  • 示例
{ path: '/user', name: 'User', meta: { title: '用户管理', perms: ['user:view'] } }

✔ 优点:

  1. 前端掌控路由、菜单,灵活更容易维护
  2. 不需要后端维护菜单表
  3. 常用于大厂 组件化、前后端分仓 的模式
  4. 权限点即可驱动显示/隐藏按钮

前端菜单只是“显示控制”,不是安全控制

就算你用后台动态返回菜单,也不能防止用户:

  1. 手动输入地址
  2. 用 F12 改源码
  3. 注入 JS
  4. 抓包直接调接口

真正的安全是 API 权限验证

所以前端写死菜单 + 权限过滤 = 大厂最佳体验

措施目的
前端菜单过滤体验层:让用户不看到没权限的东西
后端接口校验安全层:真正的权限防护(不可绕过)

后端控制实际操作

  1. 所有 API 请求都要校验用户权限
  2. 后端拿 token → 查角色 → 查 perms → 判断是否允许该操作
  3. 例如:POST /api/user/add
    • 用户 perms 包含 user:add → 允许
    • 用户 perms 不包含 user:add → 返回 403 Forbidden

重点

  1. 前端 不需要 每次请求都传 user:add
  2. 后端 通过 token 或 session 自动知道 谁在操作,然后根据权限码判断是否允许
  3. 前端只是可视化限制,真正的安全由后端负责

最终总结(Vue + React 通用)

功能点Vue3 实现React 实现
菜单写死asyncRoutesroutes.tsx
权限点存储PiniaZustand/Redux
菜单过滤filterRoutes()filterRoutes()
按钮权限v-if hasPerm()perms.includes()
安全关键必须后端接口校验必须后端接口校验

另外一种方案

菜单从后台返回(动态菜单),超级管理员添加菜单,登录后通过用户权限返回菜单的方式
流程:

  1. 超级管理员在后台添加菜单
  2. 菜单存数据库
  3. 用户登录 → 后端根据权限返回“可访问菜单树”
  4. 前端根据菜单渲染侧边栏、路由
    ✔ 优点:
  • 菜单可配置,前端不用改代码
  • 多系统保持一致
  • 超级管理员可随时调整菜单、权限
    ✘ 缺点:
  • 需要后端写复杂的“菜单树 + 角色过滤”
  • 前端路由也要动态生成
  • 有些公司根本不想把菜单配到数据库里
    现在已经放弃这个方案了
  • 大厂前端团队多,菜单都是前端组件结构
  • 菜单不需要天天变,写死才稳定
  • 权限只是控制菜单是否渲染,不需要写数据表
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 23:49:46

营销行业的 AI 助手:个性化广告语如何将转化率提升 28%?

**一、行业痛点&#xff1a;传统广告语创作的效率与效果困局在数字营销进入精细化运营的今天&#xff0c;广告语作为连接品牌与用户的关键触点&#xff0c;其创作模式正面临三重结构性矛盾。首先是创意供给与市场需求的失衡&#xff1a;据 2024 年尼尔森行业报告显示&#xff0…

作者头像 李华
网站建设 2026/4/18 7:55:37

36、Linux 技术学习与 CompTIA Linux+ 认证备考指南

Linux 技术学习与 CompTIA Linux+ 认证备考指南 1. 安全与文件权限 安全和文件权限是 Linux 系统管理中的重要部分,以下是相关的子主题及关键信息: | 子主题 | 权重 | 描述 | 关键领域 | | — | — | — | — | | 基本安全与识别用户类型 | 2 | 理解 Linux 系统上的各种…

作者头像 李华
网站建设 2026/4/18 5:28:02

4、深入探索I/O、重定向、管道和过滤器

深入探索I/O、重定向、管道和过滤器 在日常工作中,我们会接触到各种类型的文件,如文本文件、不同编程语言的源代码文件(例如 file.sh、file.c 和 file.cpp 等)。在处理这些文件或目录时,我们常常需要执行各种操作,如搜索特定字符串或模式、替换字符串、打印文件的几行内…

作者头像 李华
网站建设 2026/4/18 5:30:40

Wan2.2-T2V-A14B模型生成视频的加载速度优化策略

Wan2.2-T2V-A14B模型生成视频的加载速度优化策略 在AI内容创作迈向工业化生产的今天&#xff0c;文本到视频&#xff08;Text-to-Video, T2V&#xff09;技术正从实验室原型快速渗透至影视、广告和虚拟制作等高要求场景。阿里巴巴推出的Wan2.2-T2V-A14B作为一款具备约140亿参数…

作者头像 李华
网站建设 2026/4/18 6:26:13

千万不能错过!这家外卖点单小程序技术领先机构,竟然让商家收入

千万不能错过&#xff01;这家外卖点单小程序技术领先机构&#xff0c;竟然让商家收入翻倍引言在当今数字化时代&#xff0c;外卖点单小程序已经成为餐饮业不可或缺的一部分。随着消费者对便捷服务的需求日益增长&#xff0c;选择一个高效、稳定且功能强大的外卖点单小程序平台…

作者头像 李华