浅谈vue后台管理系统权限控制思考与实践


Posted in Javascript onDecember 19, 2018

前言

最近在开发管理系统时遇到了任何管理系统都会有的需求---权限控制,之前也遇到过这种需求,但是架构不完善导致的各种问题使得后期维护非常麻烦,这一次的方案解决了之前的种种问题,现做一次记录,当然这个架构后期可能会有坑,不过得一步一步的尝试才能发现并解决问题。

权限控制需求

因为是单页面应用,路由交给前端来控制,对于一些需要特定权限才能查看的信息的保护变得尤为重要,如果前端不做好权限校验,后端也一时疏忽,就可能就会导致数据泄露。

对于权限控制,需求大致为如下:

  1. 对于大模块的限制,比如需要通过路由跳转的模块,这时需要进行路由拦截
  2. 对于小功能的限制,比如一个按钮,如果没有特定权限,那么这个按钮就不显示

安全层面的思考

之前接手了一个管理系统,前端是将权限列表存储在storage中来实现长久储存,这种实现方式是很不可取的,因为hacker可以通过手动更改存储的信息来实现获取特定权限,甚至系统都没有做路由拦截,如果知道模块的路由,可以直接通过输入路由信息来直接跳转到特定模块。对于一些模块的权限,权限被管理员修改后也无法立即生效,所以对于这几种情况做了如下思考与实践。

权限被管理员修改后立即生效

对于这个需求,我的做法是,获取到权限列表后,将权限信息存储在 vuex store 中,并且使用getter函数,对于是否可以使用该权限进行判断,这样一旦权限数据更新,前端权限限制功能点会自动修改,从而做到权限的实时性,大致实现如下:

// vuex state.js
export default {
  userPrivileges: {
    admin: [],
    purchaser: []
  }, // 用户权限信息
}
// vuex getters.js
export default {
  canIUse: state => (role, id) => state.userPrivileges[role].includes(id)
}

// 页面具体小功能,通过 mapGetters 引入 canIUse 函数
<span v-if="canIUse('admin', 9)">{{scope.row.allocation_subtotal}}</span>

这样一来,数据存储在内存中,那么权限信息就无法轻易的被修改,同时对于权限的判断也非常简单,只需要在特定功能点传入功能点的权限id就能判断是否可以使用这个权限了。

但是将数据存储在了内存中也会遇到一个问题,页面刷新怎么办?接下来就是讲解这种情况。

刷新页面也可以进行权限判断

对于大模块的权限拦截,肯定是通过路由钩子来进行拦截的(这种实现有很多文章讲解过,这里不具体讲解),但是通过路由钩子进行拦截的前提是,权限信息得提前存在。

刷新页面会存在这种情况,页面刷新时,先执行的路由钩子,再执行的组件生命周期钩子来请求权限的列表,此时权限信息不存在,那么页面跳转到登陆页的话,体验就不够友好。

所以我的做法是,建立一个中间页,如果权限校验不通过,那么跳转至中间页,中间页进行权限的请求,请求到权限后,再判断是否可以跳转,这样的话,刷新页面体验就比较好。大致代码如下:

// vuex actions.js
// 通过返回一个promise,使得store更新与后续代码变为“同步”执行
export default {
  getUserPrivileges({ commit }) {
    return fetch.get({
      url: '/currentstaff'
    }).then(data => {
      commit('SET_USER_PRIVILEGES_INFO', data.data)
      return data.data
    }).catch(e => {

    })
  }
}
// router.js
// 需要验证权限的路由
{
  path: 'suppliers',
  component: Suppliers,
  meta: {
    role: 'admin',
    privilegeId: 5
  }
}

function isCanUseThisModule(to, from) {
  return to.matched.every(record => {
    // 利用路由meta存储相应权限信息
    if (record.meta.role) {
      return store.getters.canIUse(record.meta.role, record.meta.privilegeId)
    } else {
      return true // 如果不需要权限,直接返回true
    }
  })
}

router.beforeEach((to, from, next) => {
  if (isCanUseThisModule(to, from)) {
    next() // 权限验证通过,跳转下一路由
  } else {
    next({
      path: '/main/privilegeValidator' // 权限验证不通过时的中间页
    })
  }
})

// 权限校验中间页代码示例
created() {
  this.$store.dispatch('getUserPrivileges').then(data => {
    for (let i = 0; i < data.admin_permissions.length; i++) {
      if (this.canIUse('admin', data.admin_permissions[i])) {
        this.$router.push({
          path: this.routerList.find(value => value.privilegeId === data.admin_permissions[i]).linkHref
        })
        return
      }
    }
    this.$router.push('/login') // 如果没有任何权限,则跳转登陆页面
  })
}

用户在登陆后也可以跳转到这个权限中间页,进行权限判断后再跳转到对应模块。

尾声

大致的实现过程就是这样,希望对大家有所帮助,如果有暗坑还请指出。也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript中找到子元素在父元素内相对位置的代码
Jul 21 Javascript
JS上传图片前的限制包括(jpg jpg gif及大小高宽)等
Dec 19 Javascript
javascript实现playfair和hill密码算法
Dec 07 Javascript
使用jQuery实现更改默认alert框体
Apr 13 Javascript
JavaScript编写连连看小游戏
Jul 07 Javascript
jquery 手势密码插件
Mar 17 Javascript
Vue.js路由vue-router使用方法详解
Mar 20 Javascript
jQuery完成表单验证的实例代码(纯代码)
Sep 30 jQuery
解决在vue项目中webpack打包后字体不生效的问题
Sep 01 Javascript
JS实现的进制转换,浮点数相加,数字判断操作示例
Nov 09 Javascript
基于leaflet.js实现修改地图主题样式的流程分析
May 15 Javascript
vue实现购物车的小练习
Dec 21 Vue.js
如何为vue的项目添加单元测试
Dec 19 #Javascript
浅谈Angular7 项目开发总结
Dec 19 #Javascript
mockjs+vue页面直接展示数据的方法
Dec 19 #Javascript
vue项目搭建以及全家桶的使用详细教程(小结)
Dec 19 #Javascript
vue使用Google地图的实现示例代码
Dec 19 #Javascript
JS实现获取自定义属性data值的方法示例
Dec 19 #Javascript
vue动态绑定class选中当前列表变色的方法示例
Dec 19 #Javascript
You might like
DC动画很好看?新作烂得令人发指,名叫《红色之子》
2020/04/09 欧美动漫
PHP常用的文件操作函数经典收藏
2013/04/02 PHP
web server使用php生成web页面的三种方法总结
2013/10/28 PHP
PHP对文件夹递归执行chmod命令的方法
2015/06/19 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
laravel框架中路由设置,路由参数和路由命名实例分析
2019/11/23 PHP
javascript 动态加载 css 方法总结
2009/07/11 Javascript
JQuery 插件模板 制作jquery插件的朋友可以参考下
2010/03/17 Javascript
js将json格式内容转换成对象的方法
2013/11/01 Javascript
jQuery插件开发的五种形态小结
2015/03/04 Javascript
javascript 常见功能汇总
2015/06/11 Javascript
Javascript生成带参数的二维码示例
2016/10/10 Javascript
Angular 常用指令实例总结整理
2016/12/13 Javascript
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
2016/12/14 Javascript
Bootstrap下拉菜单Dropdowns的实现代码
2017/03/17 Javascript
使用validate.js实现表单数据提交前的验证方法
2018/09/04 Javascript
React组件对子组件children进行加强的方法
2019/06/23 Javascript
vuex 动态注册方法 registerModule的实现
2019/07/03 Javascript
vue router 跳转时打开新页面的示例方法
2019/07/28 Javascript
vue中使用v-model完成组件间的通信
2019/08/22 Javascript
原生JavaScript实现拖动校验功能
2020/09/29 Javascript
[03:00]2018完美盛典_最佳英雄奖
2018/12/17 DOTA
解决Python传递中文参数的问题
2015/08/04 Python
基于python神经卷积网络的人脸识别
2018/05/24 Python
浅谈python写入大量文件的问题
2018/11/09 Python
深入剖析webstorage[html5的本地数据处理]
2016/07/11 HTML / CSS
Superdry极度干燥美国官网:英国制造的服装品牌
2018/11/13 全球购物
什么是Connection-oriented Protocol/Connectionless Protocol面向连接的协议/无连接协议
2012/09/06 面试题
高中生校园生活自我评价
2013/09/19 职场文书
《鞋匠的儿子》教学反思
2014/03/02 职场文书
婚前协议书
2014/04/15 职场文书
竞聘上岗演讲稿
2014/05/16 职场文书
中秋节慰问信
2015/02/15 职场文书
2016年学生会感恩节活动总结
2016/04/01 职场文书
读鲁迅先生的经典名言
2019/08/20 职场文书
Promise静态四兄弟实现示例详解
2022/07/07 Javascript