当前位置: 首页 > news >正文

Pinia + Vue Router 权限控制(终极完整版)

🚀 Pinia + Vue Router 权限控制(终极完整版)


一、整体设计理念

功能说明
认证模式Token + Role + Permission
动态路由后端返回,前端动态挂载
超管放行超级管理员跳过所有权限校验
按钮权限v-permission 指令
动态标题根据路由 meta.title 自动动态设置
缓存优化Pinia 持久化,动态路由注入缓存

二、核心模块拆分

src/store/user.tspermission.tsrouter/index.tsroutes.tsutils/permission.tsdirective/permission.tsapi/user.tsviews/Layout.vueLogin.vueDashboard.vueAdmin.vueEditor.vueNotFound.vue

三、完整代码实战

1️⃣ user.ts — 用户 Store

import { defineStore } from 'pinia';export const useUserStore = defineStore('user', {state: () => ({token: '',roles: [] as string[],permissions: [] as string[],isSuperAdmin: false // 超级管理员标识}),actions: {login(token: string, roles: string[], permissions: string[]) {this.token = token;this.roles = roles;this.permissions = permissions;this.isSuperAdmin = roles.includes('super-admin');},logout() {this.token = '';this.roles = [];this.permissions = [];this.isSuperAdmin = false;}},persist: true
});

2️⃣ api/user.ts — 模拟后台接口

import type { RouteRecordRaw } from 'vue-router';export function getAsyncRoutes(): Promise<RouteRecordRaw[]> {return new Promise(resolve => {setTimeout(() => {resolve([{path: '/admin',component: () => import('@/views/Admin.vue'),meta: { title: '后台管理', roles: ['admin'], permission: 'admin:manage' }},{path: '/editor',component: () => import('@/views/Editor.vue'),meta: { title: '编辑页面', roles: ['editor'], permission: 'editor:edit' }}]);}, 300);});
}

3️⃣ permission.ts — 权限 Store

import { defineStore } from 'pinia';
import { constantRoutes } from '@/router/routes';
import type { RouteRecordRaw } from 'vue-router';
import { getAsyncRoutes } from '@/api/user';
import { useUserStore } from './user';export const usePermissionStore = defineStore('permission', {state: () => ({routes: [] as RouteRecordRaw[]}),actions: {async generateRoutes() {const userStore = useUserStore();const asyncRoutes = await getAsyncRoutes();const accessedRoutes = asyncRoutes.filter(route => {if (userStore.isSuperAdmin) return true;if (route.meta?.roles && !userStore.roles.some(role => route.meta?.roles?.includes(role))) {return false;}return true;});this.routes = constantRoutes.concat(accessedRoutes);return accessedRoutes;}}
});

4️⃣ utils/permission.ts — 按钮权限工具

import { useUserStore } from '@/store/user';export function hasPermission(permission: string): boolean {const userStore = useUserStore();return userStore.isSuperAdmin || userStore.permissions.includes(permission);
}

5️⃣ directive/permission.ts — v-permission 指令

import { Directive } from 'vue';
import { hasPermission } from '@/utils/permission';const permission: Directive = {mounted(el, binding) {const value = binding.value;if (value && !hasPermission(value)) {el.parentNode?.removeChild(el);}}
};export default permission;

全局注册:

import permission from '@/directive/permission';
app.directive('permission', permission);

使用示例:

<el-button v-permission="'admin:manage'">仅管理员按钮</el-button>

6️⃣ routes.ts — 基础路由

import type { RouteRecordRaw } from 'vue-router';export const constantRoutes: RouteRecordRaw[] = [{ path: '/login', component: () => import('@/views/Login.vue'), meta: { title: '登录' } },{path: '/',redirect: '/dashboard',component: () => import('@/views/Layout.vue'),children: [{ path: 'dashboard', component: () => import('@/views/Dashboard.vue'), meta: { title: '首页' } }]},{ path: '/:pathMatch(.*)*', component: () => import('@/views/NotFound.vue'), meta: { title: '404' } }
];

7️⃣ router/index.ts — 动态路由守卫 + 动态 Title

import { createRouter, createWebHistory } from 'vue-router';
import { constantRoutes } from './routes';
import { useUserStore } from '@/store/user';
import { usePermissionStore } from '@/store/permission';const router = createRouter({history: createWebHistory(),routes: constantRoutes
});const whiteList = ['/login'];router.beforeEach(async (to, from, next) => {const userStore = useUserStore();const permissionStore = usePermissionStore();if (to.meta?.title) {document.title = to.meta.title as string;}if (userStore.token) {if (permissionStore.routes.length === 0) {const routes = await permissionStore.generateRoutes();routes.forEach(route => router.addRoute(route));next({ ...to, replace: true });} else {next();}} else {if (whiteList.includes(to.path)) {next();} else {next('/login');}}
});export default router;

四、核心升级逻辑总结

模块升级点
超级管理员登录时 isSuperAdmin 直接放行所有路由和按钮
动态 Title每次切换路由动态修改 document.title
双重模型路由走 roles 控制,按钮走 permissions 控制

五、完整权限框架架构图

- 登录成功返回:- token- roles(角色列表)- permissions(按钮权限码)- asyncRoutes(动态路由列表)- 前端:- Pinia缓存用户信息- 动态注入路由- 路由守卫控制进入- v-permission 控制按钮显示

✅ 目前框架特点

  • 🟢 企业项目标准权限架构
  • 🟢 完整前后端配合
  • 🟢 灵活易扩展
  • 🟢 稳定性高
http://www.lryc.cn/news/572068.html

相关文章:

  • 无监督学习中的特征选择与检测(FSD)在医疗动线流程优化中的应用
  • 2025-05-05-80x86汇编语言环境配置
  • 使用随机森林实现目标检测
  • AI时代SEO关键词革新
  • 医疗低功耗智能AI网络搜索优化策略
  • 49-Oracle init.ora-PFILE-SPFILE-启动参数转换实操
  • 129. 求根节点到叶节点数字之和 --- DFS +回溯(js)
  • 详解鸿蒙Next仓颉开发语言中的全屏模式
  • 【hadoop】搭建考试环境(单机)
  • LVS+Keepalived+nginx
  • Spring Boot + MyBatis + Vue:打造高效全栈应用的黄金组合
  • Vue 组件数据流与状态控制最佳实践规范
  • 博图SCL中CONTINUE语句详解:高效循环控制案例
  • RabbitMQ多角度可靠性分析/基于Java代码深度解析
  • android 象棋游戏开发
  • Android Studio Profiler使用
  • 数据差异的iOS性能调试:设备日志导出和iOS文件管理
  • Redis之分布式锁(3)
  • 【深度学习】条件随机场(CRF)深度解析:原理、应用与前沿
  • Ubuntu 安装Telnet服务
  • Cursor Pro取消500次请求限制,无限用的体验更好了吗?
  • YOLOv8改进:Neck篇——2024.1全新MFDS-DETR的HS-FPN特征融合层解析
  • 图像特征检测算法SIFT
  • 实现自动胡批量抓取唯品会商品详情数据的途径分享(官方API、网页爬虫)
  • python校园拼团系统
  • voronoi图,凸壳,和早已遗忘的定不定积分
  • LangChain中的向量数据库抽象基类-VectorStore
  • MySQL存储引擎深度解析:InnoDB、MyISAM、MEMORY 与 ARCHIVE 的全面对比与选型建议
  • Docker PowerJob
  • 今天我想清楚了