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面向对象入门基础详细介绍
Sep 05 Javascript
利用jQuery的deferred对象实现异步按顺序加载JS文件
Mar 17 Javascript
JavaScript获取当前网页最后修改时间的方法
Apr 03 Javascript
JS排序方法(sort,bubble,select,insert)代码汇总
Jan 30 Javascript
Vue.js报错Failed to resolve filter问题的解决方法
May 25 Javascript
jQuery按需加载轮播图(web前端性能优化)
Feb 17 Javascript
webpack学习教程之publicPath路径问题详解
Jun 17 Javascript
使用nvm管理不同版本的node与npm的方法
Oct 31 Javascript
解决layui-open关闭自身窗口的问题
Sep 10 Javascript
Vue 使用Props属性实现父子组件的动态传值详解
Nov 13 Javascript
浅析Vue 防抖与节流的使用
Nov 14 Javascript
在vue中使用echarts(折线图的demo,markline用法)
Jul 20 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
收音机史话 - 1960年代前后的DIY
2021/03/02 无线电
require(),include(),require_once()和include_once()的异同
2007/01/02 PHP
php中定义网站根目录的常用方法
2010/08/08 PHP
CodeIgniter启用缓存和清除缓存的方法
2014/06/12 PHP
为PHP安装imagick时出现Cannot locate header file MagickWand.h错误的解决方法
2014/11/03 PHP
php blowfish加密解密算法
2016/07/02 PHP
详解PHP 二维数组排序保持键名不变
2019/03/06 PHP
解决Extjs 4 Panel作为Window组件的子组件时出现双重边框问题
2013/01/11 Javascript
如何让页面加载完成后执行js
2013/06/26 Javascript
JS保留两位小数,多位小数的示例代码
2014/01/07 Javascript
javascript实现在某个元素上阻止鼠标右键事件的方法和实例
2014/08/12 Javascript
js实现当鼠标移到表格上时显示这一格全部内容的代码
2016/06/12 Javascript
input file上传 图片预览功能实例代码
2016/10/25 Javascript
详谈$.data()的用法和作用
2017/02/13 Javascript
vue-cli配置环境变量的方法
2018/07/09 Javascript
javascript实现遮罩层动态效果实例
2019/05/14 Javascript
详解将微信小程序接口Promise化并使用async函数
2019/08/05 Javascript
微信小程序之侧边栏滑动实现过程解析(附完整源码)
2019/08/23 Javascript
vue created钩子函数与mounted钩子函数的用法区别
2020/11/05 Javascript
对于Python的Django框架使用的一些实用建议
2015/04/03 Python
使用python实现BLAST
2018/02/12 Python
python中单例常用的几种实现方法总结
2018/10/13 Python
Python实现多线程/多进程的TCP服务器
2019/09/03 Python
Python tkinter三种布局实例详解
2020/01/06 Python
Pycharm如何自动生成头文件注释
2020/11/14 Python
Python安装Bs4的多种方法
2020/11/28 Python
Django haystack实现全文搜索代码示例
2020/11/28 Python
实例讲解CSS3中的box-flex弹性盒属性布局
2016/06/09 HTML / CSS
HTML5之WebGL 3D概述(下)—借助类库开发及框架介绍
2013/01/31 HTML / CSS
英国皇家邮政海外旗舰店:Royal Mail
2018/02/21 全球购物
Tommy Hilfiger美国官网:美国高端休闲领导品牌
2019/01/14 全球购物
课程设计心得体会
2013/12/28 职场文书
中式结婚主持词
2014/03/14 职场文书
合作协议书模板2014
2014/09/26 职场文书
2014年师德师风自我剖析材料
2014/09/27 职场文书
优秀大学生申请书
2019/06/24 职场文书