浅谈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 相关文章推荐
js 数组实现一个类似ruby的迭代器
Oct 27 Javascript
jQuery.ajax 用户登录验证代码
Oct 29 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
Jan 23 Javascript
Jquery多选下拉列表插件jquery multiselect功能介绍及使用
May 24 Javascript
js的匿名函数使用介绍
Dec 11 Javascript
jquery实现弹出层完美居中效果
Mar 03 Javascript
自己使用js/jquery写的一个定制对话框控件
May 02 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
Mar 04 Javascript
webpack 静态资源集中输出的方法示例
Nov 09 Javascript
ES6之Proxy的get方法详解
Oct 11 Javascript
Vue中的this.$options.data()和this.$data用法说明
Jul 26 Javascript
使用Vant完成通知栏Notify的提示操作
Nov 11 Javascript
如何为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
phpmyadmin操作流程
2006/10/09 PHP
SWFUpload与CI不能正确上传识别文件MIME类型解决方法分享
2011/04/18 PHP
SESSION存放在数据库用法实例
2015/08/08 PHP
Zend Framework入门教程之Zend_Mail用法示例
2016/12/08 PHP
超强多功能php绿色集成环境详解
2017/01/25 PHP
javascript小组件 原生table排序表格脚本(兼容ie firefox opera chrome)
2012/07/25 Javascript
js分页代码分享
2014/04/28 Javascript
JavaScript异步回调的Promise模式封装实例
2014/06/07 Javascript
详解JavaScript数组的操作大全
2015/10/19 Javascript
javascript实现拖放效果
2015/12/16 Javascript
快速获取/设置iframe内对象元素的几种js实现方法
2016/05/20 Javascript
Angularjs在初始化未完毕时出现闪烁问题的解决方法分析
2016/08/05 Javascript
浅谈JS之iframe中的窗口
2016/09/13 Javascript
微信小程序 支付简单实例及注意事项
2017/01/06 Javascript
详解Jquery 遍历数组之$().each方法与$.each()方法介绍
2017/01/09 Javascript
详解动画插件wow.js的使用方法
2017/09/13 Javascript
基于vue的换肤功能的示例代码
2017/10/10 Javascript
ES6中Class类的静态方法实例小结
2017/10/28 Javascript
Vue 页面跳转不用router-link的实现代码
2018/04/12 Javascript
图片文字识别(OCR)插件Ocrad.js教程
2018/11/26 Javascript
jquery分页优化操作实例分析
2019/08/23 jQuery
详解Vue的ref特性的使用
2020/01/24 Javascript
[04:01]2014DOTA2国际邀请赛 TITAN告别Ohaiyo期望明年再战
2014/07/15 DOTA
python 写入csv乱码问题解决方法
2016/10/23 Python
Python实现可自定义大小的截屏功能
2018/01/20 Python
Python使用pandas和xlsxwriter读写xlsx文件的方法示例
2019/04/09 Python
利用matplotlib实现根据实时数据动态更新图形
2019/12/13 Python
pytorch的梯度计算以及backward方法详解
2020/01/10 Python
Tensorflow 多线程设置方式
2020/02/06 Python
印度婴儿用品在线商店:Firstcry.com
2016/12/05 全球购物
意大利领先的线上奢侈品销售电商:Eleonora Bonucci
2017/10/17 全球购物
战略合作意向书范本
2014/04/01 职场文书
2014年小学辅导员工作总结
2014/12/23 职场文书
保密法制宣传月活动总结
2015/05/07 职场文书
小程序与后端Java接口交互实现HelloWorld入门
2021/07/09 Java/Android
MySQL Server层四个日志的实现
2022/03/31 MySQL