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 相关文章推荐
前端开发必须知道的JS之原型和继承
Jul 06 Javascript
js 模拟气泡屏保效果代码
Jul 10 Javascript
ie9 提示'console' 未定义问题的解决方法
Mar 20 Javascript
JavaScript字符串对象的concat方法实例(用于连接两个或多个字符串)
Oct 16 Javascript
jQuery中DOM树操作之使用反向插入方法实例分析
Jan 23 Javascript
完美解决jQuery符号$与其他javascript 库、框架冲突的问题
Aug 09 Javascript
微信小程序 Image API实例详解
Sep 30 Javascript
bootstrap下拉列表与输入框组结合的样式调整
Oct 08 Javascript
Jquery Easyui分割按钮组件SplitButton使用详解(17)
Dec 18 Javascript
node.js操作mongodb简单示例分享
May 25 Javascript
webpack实现热更新(实施同步刷新)
Jul 28 Javascript
Vue CLI3搭建的项目中路径相关问题的解决
Sep 17 Javascript
基于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
完美解决dedecms中的[html][/html]和[code][/code]问题
2007/03/20 PHP
Excel数据导入Mysql数据库的实现代码
2008/06/05 PHP
php向js函数传参的几种方法
2014/08/10 PHP
Symfony核心类概述
2016/03/17 PHP
php抽奖概率算法(刮刮卡,大转盘)
2020/04/17 PHP
微信自定义分享php代码分析
2016/11/24 PHP
PHP/HTML混写的四种方式总结
2017/02/27 PHP
php提交表单时保留多个空格及换行的文本样式的方法
2017/06/20 PHP
laravel框架select2多选插件初始化默认选中项操作示例
2020/02/18 PHP
网站被黑的假象--ARP欺骗之页面中加入一段js
2007/05/16 Javascript
JavaScript 类的定义和引用 JavaScript高级培训 自定义对象
2010/04/27 Javascript
jquery 操作DOM案例代码分享
2012/04/05 Javascript
js控制滚动条缓慢滚动到顶部实现代码
2013/03/20 Javascript
JS弹出层单纯的绝对定位居中示例代码
2014/02/18 Javascript
详解微信小程序 wx.uploadFile 的编码坑
2017/01/23 Javascript
angularjs实现的前端分页控件示例
2017/02/10 Javascript
详解使用element-ui table组件的筛选功能的一个小坑
2018/11/02 Javascript
使用Vue实现移动端左滑删除效果附源码
2019/05/16 Javascript
使用scrapy实现爬网站例子和实现网络爬虫(蜘蛛)的步骤
2014/01/23 Python
python中的reduce内建函数使用方法指南
2014/08/31 Python
详细解读Python中的__init__()方法
2015/05/02 Python
Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】
2017/09/28 Python
python实现冒泡排序算法的两种方法
2018/03/10 Python
Python使用POP3和SMTP协议收发邮件的示例代码
2019/04/16 Python
python TK库简单应用(实时显示子进程输出)
2019/10/29 Python
使用Python和百度语音识别生成视频字幕的实现
2020/04/09 Python
Python3.8.2安装包及安装教程图文详解(附安装包)
2020/11/28 Python
div或img图片高度随宽度自适应的方法
2020/02/06 HTML / CSS
英国著名国际平价时尚男装品牌:Topman
2016/08/27 全球购物
英国最大的奢侈珠宝和手表网站:C W Sellors
2017/02/10 全球购物
美国婴儿和儿童家具网上商店:ABaby.com
2018/07/02 全球购物
平面设计求职信
2014/03/10 职场文书
社会公德演讲稿
2014/05/20 职场文书
2014年初三班主任工作总结
2014/12/05 职场文书
餐馆开业致辞
2015/08/01 职场文书
Python中re模块的元字符使用小结
2022/04/07 Python