侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Vue中实现权限控制的方法示例

前端  /  管理员 发布于 5年前   419

一、前言

在广告机项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其中根据粒的大小分的更细:

1、接口访问的权限控制

2、页面的权限控制

  • 菜单中的页面是否能被访问
  • 页面中的按钮(增、删、改)的权限控制是否显示

下面我们就看一看是如何实现这些个权限控制的。

二、接口访问的权限控制

接口权限就是对用户的校验。正常来说,在用户登录时服务器需要给前台返回一个Token,然后在以后前台每次调用接口时都需要带上这个Token,然后服务端获取到这个Token后进行比对,如果通过则可以访问。

现有的做法是在登录成功的回调中将后台返回的Token直接存储到sessionStorag​e,然在请求时将Token取出放入headers中传给后台,代码如下:

this.$http({     method: 'get',     url: 'test/query?id=20',     withCredentials: true,     headers: {      token: sessionStorage.getItem('token'),      name: sessionStorage.getItem('name')  //应后台需求传的用户名     }    }).then(response => {     //请求成功后的操作    })

后来在一些文章中发现axios可以在拦截器中直接将Token塞入config.headers.Authorization中,作为全局传入。下面是代码部分:

//main.jsimport axios from 'axios'// 实例化Axios,并进行超时设置const service = axios.create({  timeout: 5000})// baseURL// axios.defaults.baseURL = 'https://api.github.com';// http request 拦截器// 每次请求都为http头增加Authorization字段,其内容为tokenservice.interceptors.request.use(  config => {    if (store.state.user.token) {      config.headers.Authorization = `token ${store.state.user.token}`;    }    return config  },  err => {    return Promise.reject(err)  });export default service

三、页面权限控制

在前面已经说到,页面权限控制又分为两种:

  • 1菜单中的页面是否能被访问
  • 2页面中的按钮(增、删、改)的权限控制是否显示

这些权限一般是在固定页面进行配置,保存后记录到数据库中。

按钮权限暂且不提,页面访问权限在实现中又可以分为两种方式:

  • 1显示所有菜单,当用户访问不在自己权限内的菜单时,提示权限不足
  • 2只显示当前用户能访问的权限内菜单,如果用户通过URL进行强制访问,则会直接进入404

既然展现出来后不能点,那算几个意思,逗我玩儿呢?所谓眼不见为净,综合考虑后,肯定是方案二比较符合良好的用户体验。

好,我们现在梳理一下大致的页面访问权限的流程:

在这里插入图片描述

在对流程梳理完成后我们开始进行详细的编写。

1、创建路由表

创建路由表实际上没有什么难度,照着vue-router官方文档给的示例直接写就行了。但是因为有部分页面是不需要访问权限的,所以需要将登录、404、维护等页面写到默认的路由中,而将其它的需要权限的页面写到一个变量或者一个文件中,这样可以有效的减轻后续的维护压力。

下面将index.js的代码贴上,异步路由将适量减少,以免占过多篇幅。

// router/index.jsimport Vue from 'vue'import Router from 'vue-router'import App from '@/App'import store from '../store/index'Vue.use(Router);//手动跳转的页面白名单const whiteList = [ '/'];//默认不需要权限的页面const constantRouterMap = [ {  path: '/',  name: '登录',  component: (resolve) => require(['@/components/login'], resolve) }, {  path: '/index',  name: 'nav.Home',  component: (resolve) => require(['@/components/index'], resolve) }, {  path: '/templateMake',  name: '模板制作',  component: (resolve) => require(['@/components/Template/templateMake'], resolve) }, {  path: '/programMack',  name: '节目制作',  component: (resolve) => require(['@/components/Template/programMack'], resolve) }, {  path: '/release',  name: '节目发布',  component: (resolve) => require(['@/components/Program/release'], resolve) }]//注册路由export const router = new Router({ routes: constantRouterMap});//异步路由(需要权限的页面)export const asyncRouterMap = [ {  path: '/resource',  name: 'nav.Resource',  meta: {   permission: []  },  component: (resolve) => require(['@/components/Resource/resource'], resolve) }, {  path: '/template',  name: 'nav.Template',  meta: {   permission: []  },  component: (resolve) => require(['@/components/Template/template'], resolve) }, {  path: '/generalSet',  name: 'nav.System',  meta: {   permission: []  },  component: (resolve) => require(['@/components/SystemSet/generalSet'], resolve) }, {  path: '',  name: 'nav.Log',  component: App,  children: [   {    path: '/userLog',    name: 'nav.UserLog',    meta: {     permission: []    },    component: (resolve) => require(['@/components/Log/userLog'], resolve),   },   {    path: '/operatingLog',    name: 'nav.SystemLog',    meta: {     permission: []    },    component: (resolve) => require(['@/components/Log/operatingLog'], resolve),   },  ] } ]];

注意事项:这里有一个需要非常注意的地方就是 404 页面一定要最后加载,如果放在constantRouterMap一同声明了404,后面的所以页面都会被拦截到404,详细的问题见addRoutes when you've got a wildcard route for 404s does not work

2、页面访问权限

在开始时我们梳理了一个大致的页面访问权限流程。下面我们先实现最核心的部分

我们首先获取用户权限列表,在这里我们将接触到vuex状态管理,官方文档有详细介绍,这里就不过多描述了,下面请看代码:

// store/index.jsimport Axios from 'axios'import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex);const axios = Axios.create();const state = { mode: 'login', list: []};const getters = {};const mutations = { setMode: (state, data) => {  state.mode = data }, setList: (state, data) => {  state.list = data }};const actions = { // 获取权限列表 getPermission({commit}) {  return new Promise((resolve, reject) => {   axios({    url: '/privilege/queryPrivilege?id=' + sessionStorage.getItem('privId'),    methods: 'get',    headers: {     token: sessionStorage.getItem('token'),     name: sessionStorage.getItem('name')    }   }).then((res) => {    // 存储权限列表    commit('setList', res.data.cust.privileges[0].children);    resolve(res.data.cust.privileges[0].children)   }).catch(() => {    reject()   })  }) }};export default new Vuex.Store({ state, mutations, actions, getters})

好了,我们现在请求后台拿到了权限数据,并将数据存放到了vuex中,下面我们需要利用返回数据匹配之前写的异步路由表,将匹配结果和静态路由表结合,开成最终的实际路由表。

其中最关键的是利用vue-router2.2.0版本新添加的一个addRoutes方法,我们看看官方文档如何解释此方法的:

router.addRoutes(routes) 2.2.0+

动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

那我们现在就可以开始使用addRoutes进行路由匹配了。下面看代码:

// router/index.js/** * 根据权限匹配路由 * @param {array} permission 权限列表(菜单列表) * @param {array} asyncRouter 异步路由对象 */function routerMatch(permission, asyncRouter) { return new Promise((resolve) => {  const routers = [];  // 创建路由  function createRouter(permission) {     // 根据路径匹配到的router对象添加到routers中即可   permission.forEach((item) => {    if (item.children && item.children.length) {     createRouter(item.children)    }    let path = item.path;    // 循环异步路由,将符合权限列表的路由加入到routers中    asyncRouter.find((s) => {     if (s.path === '') {      s.children.find((y) => {       if (y.path === path) {        y.meta.permission = item.permission;        routers.push(s);       }      })     }     if (s.path === path) {      s.meta.permission = item.permission;      routers.push(s);     }    })   })  }  createRouter(permission)  resolve([routers]) })}

然后我们编写导航钩子

// router/index.jsrouter.beforeEach((to, form, next) => { if (sessionStorage.getItem('token')) {  if (to.path === '/') {   router.replace('/index')  } else {   console.log(store.state.list.length);   if (store.state.list.length === 0) {     //如果没有权限列表,将重新向后台请求一次    store.dispatch('getPermission').then(res => {      //调用权限匹配的方法     routerMatch(res, asyncRouterMap).then(res => {       //将匹配出来的权限列表进行addRoutes      router.addRoutes(res[0]);      next(to.path)     })    }).catch(() => {     router.replace('/')    })   } else {    if (to.matched.length) {     next()    } else {     router.replace('/')    }   }  } } else {  if (whiteList.indexOf(to.path) >= 0) {   next()  } else {   router.replace('/')  } }});

到这里我们已经完成了对页面访问的权限控制,接下来我们来讲解一下操作按扭的权限部分。

四、数据操作权限

是否还记得前面的路由配置中我们多出来的一个代码,下面我们拿出来看看:

//异步路由(需要权限的页面)export const asyncRouterMap = [ {  path: '/resource',  name: 'nav.Resource',  meta: {   permission: []  },  component: (resolve) => require(['@/components/Resource/resource'], resolve) }, {  path: '/template',  name: 'nav.Template',  meta: {   permission: []  },  component: (resolve) => require(['@/components/Template/template'], resolve) }, {  path: '/generalSet',  name: 'nav.System',  meta: {   permission: []  },  component: (resolve) => require(['@/components/SystemSet/generalSet'], resolve) }, {  path: '',  name: 'nav.Log',  component: App,  children: [   {    path: '/userLog',    name: 'nav.UserLog',    meta: {     permission: []    },    component: (resolve) => require(['@/components/Log/userLog'], resolve),   },   {    path: '/operatingLog',    name: 'nav.SystemLog',    meta: {     permission: []    },    component: (resolve) => require(['@/components/Log/operatingLog'], resolve),   },  ] } ]];

为每个路由页面增加meta字段。在routerMatch函数中将匹配到的详细权限字段赋值到这里。这样在每个页面的route对象中就会得到这个字段。

asyncRouter.find((s) => {     if (s.path === '') {      s.children.find((y) => {       if (y.path === path) {         //赋值        y.meta.permission = item.permission;        routers.push(s);       }      })     }     if (s.path === path) {      s.meta.permission = item.permission;      routers.push(s);     }    })

接下来我们编写一个vue自定义指令对页面中需要进行鉴权的元素进行判断,比如类似这样的:

 /* 3代表一个上传权限的ID,权限中有3则显示按钮 */

我们直接注册一个全局指令,利用vnode来访问vue的方法。代码如下:

//main.js//按扭权限指令Vue.directive('allow', { inserted: (el, binding, vnode) => {  let permissionList = vnode.context.$route.meta.permission;  if (!permissionList.includes(binding.value)) {   el.parentNode.removeChild(el)  } }})

至此为止,权限控制流程就已经完全结束了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

您可能感兴趣的文章:

  • 基于Vue自定义指令实现按钮级权限控制思路详解
  • 详解基于vue-router的动态权限控制实现方案
  • 基于Vue实现后台系统权限控制的示例代码
  • vue中如何实现后台管理系统的权限控制的方法示例
  • vue-router路由懒加载和权限控制详解
  • Vue2.0用户权限控制解决方案
  • vue-router 权限控制的示例代码
  • Vue2.0用户权限控制解决方案的示例
  • 如何优雅地在vue中添加权限控制示例详解


  • 上一条:
    vue 父组件中调用子组件函数的方法
    下一条:
    利用Vue-draggable组件实现Vue项目中表格内容的拖拽排序
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客