vue权限问题的完美解决方案


Posted in Javascript onMay 08, 2019

前言

最近一直在忙着一个用vue来做的权限管理的项目,其实在此之前,我也研究过vue的权限如何实现,并且也为之写过一篇博客,但当真正应用在项目中的时候,还是发现了许多问题,所以此篇也会就着我在项目中遇到的一些问题,拿出来和大家分享一下,当然示例代码还是我的github仓库中的ant-design-vue-ms (本地下载)。

权限问题解决思路

对于一个前后端分离的项目而言,权限不再是仅仅靠后端来控制,后端只能控制接口的权限,前台的页面显示还是需要我们来控制,针对vue的项目,首先我想的是当权限不多,并且都是单个权限的情况下,我们完全没有必要使用vue中提供的addRoutes的方法,可以使用动态组件来做,即我们根据后端返回的角色,来细度控制动态组件的显示内容,所谓动态组件其实就是vue内置提供的component组件

<component :is="currentComponent"/>

相信看到这里,熟悉的同学应该已经想起来了,这样的话,我们就不需要用到vuex,以及路由配置等等复杂的问题,单纯靠后台返回的角色名称就能解决所有的问题了,看到这里是不是觉得今天的内容就这些了,别着急,下面还有“好看的”。

权限设置中的问题

这样虽然能解决一些简单权限的问题,但是针对稍微复杂一些的权限应用,就显得有些力不从心了,当角色过多,并且还包含了混合角色的权限的话,则会衍生出很多问题,这里也是列举我遇到的一些问题,同学们可以细细推敲一下。

  • 如果是混合角色的话,动态组件的路由跳转实际都是跳转到一个页面,但是混合角色肯定会一个页面中跳到不同角色的页面,这样可能我们要多写很多层的判断,权限混合越多,就越难以去判断。
  • 动态组件扩展性比较差,如果我们再添加一个权限呢,就要再多加一个动态组件的内容,并且出现混合权限的话,那改动的地方就更多了

所以综上所述,最终我还是选择了传统的addRoutes,那么肯定会有同学问了,既然这个方案不行,那干嘛还要用呢。问得好,其实动态组件就是一种尝试,只有知道错了,不满足需求了,我们才能更知道为什么会去使用传统的addRoutes的权限方案。

权限问题解决方法

所以我们来看看addRoutes带来的一些“好处”:

  • 一次配置,多处使用,我们配置好了动态路由以后,不论后期添加多少权限,都能很好的显示路由跳转等等,并且也不需要改动代码,只需要添加新增角色的模块就可以了。
  • 遇到混合角色的问题,如果内容布局类似的话,我们可以使用自定义指令来区分要显示的模块,这样的话如果一个账号同时拥有很多角色的话,那么包含这个角色的模块则会相应的显示出来,就不会出现需要判断究竟显示哪个模块了,也不需要单独为某个角色去设置一个页面来显示了。

相信做过权限的同学对上面的内容还是有一些心得的,然后我们按照该有的步骤一步一步来,这些步骤在上面我的github中已经有了,大家可以对照一下。

1、全局导航守卫的设置,此处设置全局导航守卫,我觉得更多是为了数据持久化,大家都知道,vuex虽然非常好用,但是会有刷新丢失数据的情况,因此针对这种情况,我们使用导航守卫,每次刷新的时候,会重新请求后台的接口来获取角色信息。

if (store.getters.roles.length === 0) {
  store
   .dispatch('GetInfo')
   .then(res => {
   const roles = res.data.resultData && res.data.resultData.roles
   store.dispatch('GenerateRoutes', { roles }).then(() => {
    // 根据roles权限生成可访问的路由表
    // 动态添加可访问路由表
    router.addRoutes(store.getters.addRouters)
   })
   })
   .catch(() => {
   store.dispatch('Logout').then(() => {
    next({ path: '/user/login', query: { redirect: to.fullPath } })
   })
   })
  } else {
  next()
  }

这里代码做了简化,主要给大家看下上面会有一个角色判断长度,主要是当我们不刷新的情况,页面角色信息不回丢失,因此我们也就没有必要去请求后台获取角色信息了,来节省请求数量。

2. 通过上面的代码可以看到,我们首先是请求的角色信息,然后请求了生成路由的GenerateRoutes的方法,方法是写在vuex中的action里面的,这部分的内容因为网上有很多教程,其实主要归纳一下,就是对路由进行递归过滤,过滤出符合角色的路由,然后将静态路由和过滤出来的动态路由链接起来

const permission = {
 state: {
 routers: constRouterMap,
 addRouters: []
 },
 mutations: {
 SET_ROUTERS: (state, routers) => {
  state.addRouters = routers
  state.routers = constRouterMap.concat(routers)
 }
 },
 actions: {
 GenerateRoutes({ commit }, data) {
  //略
 }
 }
}

3、设置我们的路由文件,这部分放到这里来说,主要因为这里还有个小坑,所以也是特地拿出来和大家分享一下

export const constRouterMap = [
 {
  path: '/',
  redirect: '/index',
  component: BasicLayout,
  children: [
   {
    path: '/index',
    name: 'index',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
    meta: {
     title: '仪表盘'
    }
   },
   {
    path: '/home',
    name: 'home',
    component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue'),
    meta: {
     title: '表单页'
    }
   },
   {
    path: '/pattern',
    name: 'pattern',
    component: () => import(/* webpackChunkName: "pattern" */ '@/views/DesignPattern.vue')
   },
   {
    path: '/map',
    name: 'map',
    component: () => import(/* webpackChunkName: "map" */ '@/views/DataMap.vue'),
    meta: {
     title: '地图组件'
    }
   },
  ]
 },
 {
  path: '/user',
  redirect: '/login',
  component: UserLayout,
  children: [
   {
    path: '/login',
    name: 'login',
    component: () => import(/* webpackChunkName: "login" */ '@/views/user/Login.vue')
   },
   {
    path: '/register',
    name: 'register',
    component: () => import(/* webpackChunkName: "login" */ '@/views/user/Register.vue')
   }
  ]
 },
 //需要注意这里,404的路由一定要写在静态路由中
 {
  path: '/404',
  component: () => import(/* webpackChunkName: "not_found" */ '@/views/NotFound.vue')
 }
]

export const asyncRouterMap = [
 {
  path: '/',
  redirect: '/index',
  component: BasicLayout,
  children: [
   {
    path: '/controls',
    name: 'controls',
    component: () => import(/* webpackChunkName: "controls" */ '@/views/Controls.vue'),
    meta: {
     title: '权限设置',
     permission: ['admin']
    }
   }
  ]
 },
 //捕获未定义的路由配置
 {
  path: '*',
  redirect: '/404',
  hidden: true
 }
]

上面关于404页面的定义顺序非常重要,如果在静态路由中定义了捕获的路由path:"*",而在动态路由中定义了404路由的话,则当导航钩子中判断比较复杂的话,会出现一些意想不到的错误,我就是当时写反了顺序,并且还在导航钩子中做了一些复杂的面包屑的判断,一旦刷新页面的话,则会出现以下错误

vue权限问题的完美解决方案

这种错误的产生,可能是因为刷新时,导航钩子发现动态添加进来的路由找不到一直进行获取动态路由的方法,导致最后调用栈溢出所导致,因此大家在使用的时候一定要非常小心。

4. 当我们生成路由后,退出应用的切换新的角色账号进行登录时,一定要记得的两件事,第一就是清空vuex里面的角色信息,在不刷新的情况下,这些信息是不会丢失的,当不同角色的账号登录时,原来的角色依然存在,那么肯定会出现问题,其次则是在跳转会登录页的时候,需要设置刷新页面的代码

window.location.reload();
this.$router.push({name: 'login'});

先刷新以后再跳转到登录页,这个则是因为addRoutes生成的路由在不刷新的情况下会一直存在,即使下个不同角色的账号登录时,依然会拿之前存在的路由信息去进行过滤,这样过滤的结果必然是当前角色的路由一个都不存在,因此生成的路由信息还是上个角色的路由,所以在完成了之前这些步骤时,一定不要忘记了做这两步,这样也才是一个完整的权限解决方案

尾声

以上也是我在项目中一些收货吧,拿出来和大家分享,也是希望大家少走一些弯路,留心我们开发中遇到的每个看似很小的问题,其实往往是我们最后解决问题的关键,不论是从动态组件还是动态路由,问题的出现也是我们不断去完善自己的过程。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript之大字符串的连接的StringBuffer 类
May 08 Javascript
JavaScript获取页面上某个元素的代码
Mar 13 Javascript
最短的IE判断var ie=!-[1,]分析
May 28 Javascript
BootStrap 可编辑表Table格
Nov 24 Javascript
JS基于面向对象实现的拖拽功能示例
Dec 20 Javascript
jQuery编写textarea输入字数限制代码
Mar 23 jQuery
React数据传递之组件内部通信的方法
Dec 31 Javascript
vue里面v-bind和Props 利用props绑定动态数据的方法
Aug 27 Javascript
JS实现字符串翻转的方法分析
Aug 31 Javascript
前后端如何实现登录token拦截校验详解
Sep 03 Javascript
JS实现将对象转化为数组的方法分析
Jan 21 Javascript
基于VUE实现简单的学生信息管理系统
Jan 13 Vue.js
基于vue-cli 路由 实现类似tab切换效果(vue 2.0)
May 08 #Javascript
微信小程序事件对象中e.target和e.currentTarget的区别详解
May 08 #Javascript
利用原生JavaScript实现造日历轮子实例代码
May 08 #Javascript
Vue2.0使用嵌套路由实现页面内容切换/公用一级菜单控制页面内容切换(推荐)
May 08 #Javascript
vue实现菜单切换功能
May 08 #Javascript
浅谈JS的原型和继承
May 08 #Javascript
vue使用vuex实现首页导航切换不同路由的方法
May 08 #Javascript
You might like
杏林同学录(四)
2006/10/09 PHP
一个简单的域名注册情况查询程序
2006/10/09 PHP
基于pear auth实现登录验证
2010/02/26 PHP
php使用ereg验证文件上传的方法
2014/12/16 PHP
PHP的Laravel框架中使用AdminLTE模板来编写网站后台界面
2016/03/21 PHP
PHP简单获取上月、本月、近15天、近30天的方法示例
2017/07/03 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
2017/09/17 PHP
PHP实现从上往下打印二叉树的方法
2018/01/18 PHP
laravel框架select2多选插件初始化默认选中项操作示例
2020/02/18 PHP
利用jQuery接受和处理xml数据的代码(.net)
2011/03/28 Javascript
Jquery阻止事件冒泡 event.stopPropagation
2011/12/11 Javascript
javascript 获取HTML DOM父、子、临近节点
2014/06/16 Javascript
ES6新特性:使用export和import实现模块化详解
2017/07/31 Javascript
浅谈vue单一组件下动态修改数据时的全部重渲染
2018/03/01 Javascript
JavaScript捕捉事件和阻止冒泡事件实例分析
2018/08/03 Javascript
[原创]微信小程序获取网络类型的方法示例
2019/03/01 Javascript
jQuery实现鼠标拖动图片功能
2021/03/04 jQuery
python strip()函数 介绍
2013/05/24 Python
跟老齐学Python之再深点,更懂list
2014/09/20 Python
Windows下用py2exe将Python程序打包成exe程序的教程
2015/04/08 Python
python实现将元祖转换成数组的方法
2015/05/04 Python
详解Python中 __get__和__getattr__和__getattribute__的区别
2016/06/16 Python
PyCharm代码回滚,恢复历史版本的解决方法
2018/10/22 Python
Python openpyxl 遍历所有sheet 查找特定字符串的方法
2018/12/10 Python
python中pygame安装过程(超级详细)
2019/08/04 Python
初次部署django+gunicorn+nginx的方法步骤
2019/09/11 Python
基于python实现对文件进行切分行
2020/04/26 Python
Python实现Keras搭建神经网络训练分类模型教程
2020/06/12 Python
python opencv角点检测连线功能的实现代码
2020/11/24 Python
详解Pymongo常用查询方法总结
2021/01/29 Python
英语教学随笔感言
2014/02/20 职场文书
有趣的广告词
2014/03/18 职场文书
《月亮湾》教学反思
2014/04/14 职场文书
2014年学习厉行节约反对浪费思想汇报
2014/09/10 职场文书
产品委托授权书范本
2014/09/16 职场文书
统计工作个人总结
2015/03/03 职场文书