0

0

vue+vue-router+vuex操作权限

php中世界最好的语言

php中世界最好的语言

发布时间:2018-05-14 13:58:24

|

3603人浏览过

|

来源于php中文网

原创

这次给大家带来vue+vue-router+vuex操作权限,vue+vue-router+vuex操作权限的注意事项有哪些,下面就是实战案例,一起来看一下。

基于vuex, vue-router,vuex的权限控制教程,完整代码地址见 https://github.com/linrunzheng/vue-permission-control

接下来让我们模拟一个普通用户打开网站的过程,一步一步的走完整个流程。

首先从打开本地的服务localhost:8080开始,我们知道打开后会进入login页面,那么判断的依据是什么。

首先是token。

没有登陆的用户是获取不到token的,而登陆后的角色我们会将token存到local或者seesionStorage 因此,根据当前有没有token即可知道是否登陆。

为了存取token并且方便我们操作,可以配和vuex实现

/* state.js */
export default {
 get UserToken() {
 return localStorage.getItem('token')
 },
 set UserToken(value) {
 localStorage.setItem('token', value)
 }
}
/* mutation.js */
export default {
 LOGIN_IN(state, token) {
 state.UserToken = token
 },
 LOGIN_OUT(state) {
 state.UserToken = ''
 }
}

拦截的判断

没有token进入需要权限的页面:redirect到login页面

由于我们路由是动态挂载的,包括 ' ' 和404,所以当匹配不到路由时,也重定向到login

router.beforeEach((to, from, next) => {
 if (!store.state.UserToken) {
 if (
 to.matched.length > 0 &&
 !to.matched.some(record => record.meta.requiresAuth)
 ) {
 next()
 } else {
 next({ path: '/login' })
 }
 } 
})

好了,此时用户打开localhost:8080,默认匹配的是''路径,此时我们并没有挂载路由,也没有token,所以来到了login。

输入用户名密码后,有token了,通过store触发* commit('LOGIN_IN')* 来设置token。

但是还是没有路由,目前最开始只有login路由

/* 初始路由 */
export default new Router({
 routes: [
 {
 path: '/login',
 component: Login
 }
 ]
})
/* 准备动态添加的路由 */
export const DynamicRoutes = [
 {
 path: '',
 component: Layout,
 name: 'container',
 redirect: 'home',
 meta: {
 requiresAuth: true,
 name: '首页'
 },
 children: [
 {
 path: 'home',
 component: Home,
 name: 'home',
 meta: {
  name: '首页'
 }
 }
 ]
 },
 {
 path: '/403',
 component: Forbidden
 },
 {
 path: '*',
 component: NotFound
 }
]

我们要根据当前用户的token去后台获取权限。

由于权限这块逻辑还挺多,所以在vuex添加了一个permission模块来处理权限。

为了判断是已有路由列表,需要在vuex的permission模块存一个state状态permissionList用来判断,假如permissionList不为null,即已经有路由,如果不存在,就需要我们干活了。

router.beforeEach((to, from, next) => {
 if (!store.state.UserToken) {
 ...
 } else {
 /* 现在有token了 */
 if (!store.state.permission.permissionList) {
 /* 如果没有permissionList,真正的工作开始了 */
 store.dispatch('permission/FETCH_PERMISSION').then(() => {
 next({ path: to.path })
 })
 } else {
 if (to.path !== '/login') {
 next()
 } else {
 next(from.fullPath)
 }
 }
 }
})

来看一下 store.dispatch('permission/FETCH_PERMISSION') 都干了什么

actions: {
 async FETCH_PERMISSION({ commit, state }) {
 /* 获取后台给的权限数组 */
 let permissionList = await fetchPermission()
 /* 根据后台权限跟我们定义好的权限对比,筛选出对应的路由并加入到path=''的children */
 let routes = recursionRouter(permissionList, dynamicRouter)
 let MainContainer = DynamicRoutes.find(v => v.path === '')
 let children = MainContainer.children
 children.push(...routes)
 /* 生成左侧导航菜单 */
 commit('SET_MENU', children)
 setDefaultRoute([MainContainer])
 /* 初始路由 */
 let initialRoutes = router.options.routes
 /* 动态添加路由 */
 router.addRoutes(DynamicRoutes)
 /* 完整的路由表 */
 commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])
 }
}

首先,await fetchPermission()获取后台给的权限数组,格式大概如下

{
 "code": 0,
 "message": "获取权限成功",
 "data": [
 {
 "name": "订单管理",
 "children": [
 {
  "name": "订单列表"
 },
 {
  "name": "生产管理",
  "children": [
  {
  "name": "生产列表"
  }  
  ]
 },
 {
  "name": "退货管理"
 }
 ]
 }
 ]
}

其次根据我们写好的路由数组,进行对比,过滤得到我们要的路由

/* 这里是我们写好的需要权限判断的路由 */
const dynamicRoutes = [
 {
 path: '/order',
 component: Order,
 name: 'order-manage',
 meta: {
 name: '订单管理'
 },
 children: [
 {
 path: 'list',
 name: 'order-list',
 component: OrderList,
 meta: {
  name: '订单列表'
 }
 },
 {
 path: 'product',
 name: 'product-manage',
 component: ProductManage,
 meta: {
  name: '生产管理'
 },
 children: [
  {
  path: 'list',
  name: 'product-list',
  component: ProductionList,
  meta: {
  name: '生产列表'
  }
  },
  {
  path: 'review',
  name: 'review-manage',
  component: ReviewManage,
  meta: {
  name: '审核管理'
  }
  }
 ]
 },
 {
 path: 'returnGoods',
 name: 'return-goods',
 component: ReturnGoods,
 meta: {
  name: '退货管理'
 }
 }
 ]
 }
]
export default dynamicRoutes

为了对比,我写好了一个递归函数,用name和meta.name进行对比 ,根据这个函数就可以得到我们想要的结果

/**
 *
 * @param {Array} userRouter 后台返回的用户权限json
 * @param {Array} allRouter 前端配置好的所有动态路由的集合
 * @return {Array} realRoutes 过滤后的路由
 */
export function recursionRouter(userRouter = [], allRouter = []) {
 var realRoutes = []
 allRouter.forEach((v, i) => {
 userRouter.forEach((item, index) => {
 if (item.name === v.meta.name) {
 if (item.children && item.children.length > 0) {
  v.children = recursionRouter(item.children, v.children)
 }
 realRoutes.push(v)
 }
 })
 })
 return realRoutes
}

得到过滤后的数组后,加入到path为''的children下面

{
 path: '',
 component: Layout,
 name: 'container',
 redirect: 'home',
 meta: {
 requiresAuth: true,
 name: '首页'
 },
 children: [
 {
 path: 'home',
 component: Home,
 name: 'home',
 meta: {
  name: '首页'
 }
 },
 <!-- 将上面得到的东西加入到这里 -->
 ...
 ]
 }

这个时候,path为''的children就是我们左侧的导航菜单了,存到state的sidebarMenu待用。加入到children后,这时DynamicRoutes就可以加入到路由了。

/* 动态添加路由 */
router.addRoutes(DynamicRoutes)
 /* 初始路由 */
let initialRoutes = router.options.routes
/* 合并起来,就是完整的路由了 */
commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])

路由添加完了,也就是action操作完毕了,即可在action.then里面调用 next({ path: to.path })进去路由,这里要注意, next里面要传参数即要进入的页面的路由信息,因为next传参数后,当前要进入的路由会被废止,转而进入参数对应的路由,虽然是同一个路由,这么做主要是为了确保addRoutes生效了。

进入路由后,要开始生成左侧菜单,之前我们已经存到sidebarMenu了,现在需要做的只是递归生成菜单而已,虽然用了element的导航菜单,但是为了递归路由,还需要自己封装一下。这里核心的地方是组件的name,在组件里面有children的地方,又再次使用自己,从而遍历整个tree结构的路由。

<template>
 <p class="menu-container">
 <template v-for="v in menuList">
 <el-submenu :index="v.name" v-if="v.children&&v.children.length>0" :key="v.name">
 <template slot="title">
  <i class="iconfont icon-home"></i>
  <span>{{v.meta.name}}</span>
 </template>
 <el-menu-item-group>
  <my-nav :menuList="v.children"></my-nav>
 </el-menu-item-group>
 </el-submenu>
 <el-menu-item :key="v.name" :index="v.name" @click="gotoRoute(v.name)" v-else>
 <i class="iconfont icon-home"></i>
 <span slot="title">{{v.meta.name}}</span>
 </el-menu-item>
 </template>
 </p>
</template>
<script>
export default {
 name: 'my-nav',
 props: {
 menuList: {
 type: Array,
 default: function() {
 return []
 }
 }
 },
 methods: {
 gotoRoute(name) {
 this.$router.push({ name })
 }
 }
}
</script>

刷新页面后,根据我们router.beforeEach的判断,有token但是没permissionList,我们是会重新触发action去获取路由的,所以无需担心。但是导航菜单active效果会不见。不过我们已经把el-menu-item的key设置为路由的name,那么我们只要在刷新后,在afterEach把当前路由的name赋值给el-menu default-active即可。同理,在afterEach阶段获取所有matched的路由,即可实现面包屑导航

if (!store.state.permission.permissionList) {
 store.dispatch('permission/FETCH_PERMISSION').then(() => {
 next({ path: to.path })
 })
} 
...
router.afterEach((to, from, next) => {
 var routerList = to.matched
 store.commit('setCrumbList', routerList)
 store.commit('permission/SET_CURRENT_MENU', to.name)
})

退出登陆后,需要刷新页面,因为我们是通过addRoutes添加的,router没有deleteRoutes这个api,所以清除token,清除permissionList等信息,刷新页面是最保险的。

最后还有一点,每次请求得带上token, 可以对axios封装一下来处理

var instance = axios.create({
 timeout: 30000,
 baseURL
})
// 添加请求拦截器
instance.interceptors.request.use(
 function(config) {
 // 请求头添加token
 if (store.state.UserToken) {
 config.headers.Authorization = store.state.UserToken
 }
 return config
 },
 function(error) {
 return Promise.reject(error)
 }
)
/* axios请求二次封装 */
instance.get = function(url, data, options) {
 return new Promise((resolve, reject) => {
 axios
 .get(url, data, options)
 .then(
 res => {
  var response = res.data
  if (response.code === 0) {
  resolve(response.data)
  } else {
  Message.warning(response.message)
  /* reject(response.message) */
  }
 },
 error => {
  if (error.response.status === 401) {
  Message.warning({
  message: '登陆超时,请重新登录'
  })
  store.commit('LOGIN_OUT')
  window.location.reload()
  } else {
  Message.error({
  message: '系统异常'
  })
  }
  reject(error)
 }
 )
 .catch(e => {
 console.log(e)
 })
 })
}
export default instance

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

PixVerse
PixVerse

PixVerse是一款强大的AI视频生成工具,可以轻松地将多种输入转化为令人惊叹的视频。

下载

react router4+redux控制路由权限步骤详解

v-bind与v-on使用案例详解

Vue表单类父子组件数据传递数据方法总结

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

46

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

178

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

51

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

92

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

102

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

227

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

532

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

171

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
uni-app电商系统实战精讲课程
uni-app电商系统实战精讲课程

共66课时 | 15.7万人学习

ThinkPHP配置开发与CMS后台实战
ThinkPHP配置开发与CMS后台实战

共87课时 | 9.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号