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中的细节分析
Jun 30 Javascript
JS打印gridview实现原理及代码
Feb 05 Javascript
jquery.post用法之type设置问题
Feb 24 Javascript
推荐9款炫酷的基于jquery的页面特效
Dec 07 Javascript
5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例
Jan 29 Javascript
Javascript刷新窗口方法小结
Oct 21 Javascript
基于MVC4+EasyUI的Web开发框架形成之旅之界面控件的使用
Dec 16 Javascript
JQuery异步加载PartialView的方法
Jun 07 Javascript
Node.js 8 中的 util.promisify的详解
Jun 12 Javascript
微信小程序时间控件picker view使用详解
Dec 28 Javascript
在微信小程序中渲染HTML内容3种解决方案及分析与问题解决
Jan 12 Javascript
JavaScript实现多文件下载方法解析
Aug 07 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
php从字符串创建函数的方法
2015/03/16 PHP
PHP执行shell脚本运行程序不产生core文件的方法
2016/12/28 PHP
php json转换相关知识(小结)
2018/12/21 PHP
使用prototype.js进行异步操作
2007/02/07 Javascript
Javascript中暂停功能的实现代码
2007/03/04 Javascript
Javascript 读后台cookie代码
2008/09/15 Javascript
javascript操作cookie的文章(设置,删除cookies)
2010/04/01 Javascript
jQuery参数列表集合
2011/04/06 Javascript
JQuery中html()方法使用不当带来的陷阱
2011/04/07 Javascript
通过javascript把图片转化为字符画
2013/10/24 Javascript
利用JQuery和Servlet实现跨域提交请求示例分享
2014/02/12 Javascript
js实现C#的StringBuilder效果完整实例
2015/12/22 Javascript
JavaScript中数组slice和splice的对比小结
2016/09/22 Javascript
微信小程序 摇一摇抽奖简单实例实现代码
2017/01/09 Javascript
angular实现form验证实例代码
2017/01/17 Javascript
关于layui的下拉搜索框异步加载数据的解决方法
2019/09/28 Javascript
微信小程序动态添加和删除组件的现实
2020/02/28 Javascript
简单介绍Python中的struct模块
2015/04/28 Python
python实现上传下载文件功能
2020/11/19 Python
python 类对象和实例对象动态添加方法(分享)
2017/12/31 Python
Pycharm 文件更改目录后,执行路径未更新的解决方法
2019/07/19 Python
Python pandas如何向excel添加数据
2020/05/22 Python
Python datetime模块使用方法小结
2020/06/18 Python
使用CSS3滤镜的filter:blur属性制作毛玻璃模糊效果的方法
2016/07/08 HTML / CSS
英国领先的男装设计师服装独立零售商:Repertoire Fashion
2020/10/19 全球购物
销售高级职员求职信
2013/10/29 职场文书
电子信息工程专业推荐信
2014/02/14 职场文书
正风肃纪剖析材料
2014/02/18 职场文书
教师个人读书活动总结
2014/07/08 职场文书
艺术学院毕业生求职信
2014/07/09 职场文书
结对共建协议书
2014/08/20 职场文书
小学师德师风演讲稿
2014/09/02 职场文书
村党支部书记四风问题个人对照检查材料思想汇报
2014/10/06 职场文书
公司周年庆寄语
2019/06/21 职场文书
最新的离婚协议书范本!
2019/07/02 职场文书
Windows11 Insider Preview Build 25206今日发布 更新内容汇总
2022/09/23 数码科技