手把手教学vue的路由权限问题

目录
  • 菜单权限
    • 相关知识点了解
    • 知识点集结
    • 功能实现过程
  • 按钮权限 - 操作(自定义指令)
  • 总结

后台管理类系统大多都涉及权限管理,菜单权限,按钮权限。

菜单权限

菜单权限对应 - 路由。菜单权限 - 根据用户角色不同,路由文件动态配置。

相关知识点了解

vue-router

vue-router是vue项目在进行开发过程中必不可少缺少的插件,目前vue2依赖的是vue-router3,vue3依赖的vue-router4

在进行权限控制之前一定要了解哪些路由需要权限哪些不需要

知识点集结

  • router.addRoutes()

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

已废弃目前版本再使用该api会被提示已经废弃,但是暂时依旧可以使用

router.addRoutes(routes: Array<RouteConfig>)
  • router.addRoute()

添加一条新路由规则。如果该路由规则有 name,并且已经存在一个与之相同的名字,则会覆盖它。

addRoute(route: RouteConfig)
  • router.getRoutes()

获取所有活跃的路由记录列表。注意只有文档中记录下来的 property 才被视为公共 API,避免使用任何其它 property,例如 regex,因为它在 Vue Router 4 中不存在。

路由导航守卫 - beforeEach

router.beforeEach((to, from, next) => {
  /* 必须调用 `next` */
})

全局前置守卫 - 跳转一个路由之前都会执行.

3个参数:

  • to: 即将进入的目标的路由对象
  • from:当前导航正在离开的路由
  • next: 是个函数,进入下一个钩子
  • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
  • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
  • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

功能实现过程

路由权限第一种可以是后端全部返回,直接调用接口使用后端的可以使用的路由,但是这种情况一般较少。

第二种前端有一个份完整路由,根据后端接口进行筛选,这里讲解第二种情况。

(1)定义路由文件

router -> index.js

import Vue from 'vue'
import Router from 'vue-router'
import store  from '../store'

Vue.use(Router)

//没有权限的路由
export const constantRoutes = [
  { path: '/', name: 'index', redirect: '/login' },
  { path: '/login', name: 'login', component: () => import('@/views/login') },
  { path: '/register', name: 'register', component: () => import('@/views/register') },
  { path: '/forget', name: 'forget', component: () => import('@/views/forget') },
  { path: '/404', name: 'notfing', component: () => import('@/views/404')}
]

//有权限的路由
export const  myAsyncRoute = [{
  path: '/portal',
  name: 'portal',
  component: LayoutPortal,
  redirect: '/portal/home',
  meta: {id: 'no'},
  children: [
    {
      path: '/portal/home',
      name: 'portal-home',
      component: () => import('@/views/portal/home/index.vue'),
      meta: {id: 100100, title: '首页', show: true}
    },
    {
      path: '/portal/user',
      name: 'portal-user',
      component: () => import('@/views/layout/submenu'),
      meta: {id: 100200, title: '统一身份认证', show: true},
      redirect: '/portal/user/userInfo',
      children: [
        {
          path: '/portal/user/userInfo',
          name: 'portal-user-userInfo',
          component: () => import('@/views/portal/userInfo/index.vue'),
          meta: {id: 100201, title: '统一用户管理', show: true}
        },
        {
          path: '/portal/user/userInfo/detial',
          name: 'portal-userInfo-detial',
          component: () => import('@/views/portal/userInfo/detial.vue'),
          meta: { id: 100201, activeMenu: '/portal/user/userInfo', title: '统一用户管理', show: false},
        },
        {
          path: '/portal/user/userAuth',
          name: 'portal-user-userAuth',
          component: () => import('@/views/portal/userAuth/index.vue'),
          meta: {id: 100202, title: '用户认证', show: true}
        },
      ]
    },
    {
      path: '/portal/journal',
      name: 'portal-journal',
      component: () => import('@/views/portal/journal/index.vue'),
      meta: {id: 100303, title: '统一日志管理', show: true},
    },
    {
      path: 'personal',
      name: 'portal-personal',
      component: () => import('@/views/portal/personal/index.vue'),
      meta: {
        id: 'no',
        activeMenu: '/portal/home',
        show: false
      },
    },
  ],
}]

export default new Router({
  routes: constantRoutes,
})

(2)注册路由

main.js

import router from './router'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

正常注册完路由就可以开始进行权限设置了

(3)获取有权限路由

不同的项目获取路由权限并不相同,大多数 - 登录接口返回/单独接口进行获取

登录获取权限保存

let res = await this.$api.user.login(data);
 if(res.token) {
      this.$store.commit('setToken', res.token);
      this.$store.commit('setUsername', res.nickName);
      this.$store.commit('setUserInfo', res);
      //存储权限
      localStorage.setItem('menuIdList', JSON.stringify(res.menuIdList))
           this.$message({
              message: '登录成功',
              type: 'success'
            });

            setTimeout(() => {
               this.loading = false;
               this.$router.push('/portal')
            }, 1000);
   }

在main.js中拦截 

获取权限进行匹配 - beforeEach一定要有一个next()的出口,不然会陷入死循环

let flag = true;
router.beforeEach((to, from, next) => {
  if (['/login', '/forget', '/register'].includes(to.path)) {
    next();
  } else {
    let token = localStorage.getItem("token");
    if (token) {
      if(flag) {
        try {
          //获取有权限的路由进行组装
          let route = asyncRoute() || [];
          router.addRoutes(route)
          router.addRoute({
            path: '*',
            redirect: '/404'
          })
          flag = false
          next({...to, replace:true})
        }catch(e) {
          next('/login')
        }
       }else {
         next();
       }
      }else {
        next({ path: '/login' })
      }
    }
  }
);

注意: addRoute之后,打印router是看不见的,要获取所有的权限,必须使用router.getRoute()进行查看

(4)路由权限匹配

router.js-根据后端返回的权限,和自己的路由权限匹配,组织成新的路由,和自己想要的格式

export const asyncRoute = function() {
  let menuIdList = localStorage.getItem('menuIdList') ? JSON.parse(localStorage.getItem('menuIdList')) : [];

  let tempArr = filterRoute(myAsyncRoute, menuIdList);

  store.dispatch('getRoute', tempArr)

  let showRoute = [];
  let nowRoute =JSON.parse(JSON.stringify(tempArr))
  if(nowRoute[0].children && nowRoute[0].children.length){
    nowRoute[0].children.forEach(item => {
      let arr = [];
      if(item.children && item.children.length){
        arr = item.children.filter(obj => obj.meta.show)
      }
      if(item.meta.show){
        item['showRouteChildren'] = arr;
        showRoute.push(item)
      }
    })
  }
  store.dispatch('getShowRoute', showRoute)

  return tempArr
}

function filterRoute(arr, menuIdList) {
  if(!arr.length) return [];
  return arr.filter(item => {
    if(item.children && item.children.length) {
      item.children = filterRoute(item.children, menuIdList);
    }
    return (item.meta && item.meta.id && menuIdList.includes(item.meta.id)) || (item.meta && item.meta.id == 'no') || (item.children && item.children.length > 0)
  })
}

在这个过程中,在store存储了路由

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        routes: JSON.parse(localStorage.getItem('routes')) ||  [],
        addRoutes: JSON.parse(localStorage.getItem('addRoutes')) ||[],
        showRoutes: []
    },
    mutations: {
        setRoutes(state, routes) {
            state.addRoutes = routes;
            state.routes = constantRoutes.concat(routes)
            localStorage.setItem('routes', JSON.stringify(state.routes))
            localStorage.setItem('addRoutes', JSON.stringify(state.addRoutes))
        },
        setShowRoutes(state, routes) {
            state.showRoutes = routes;
        }
    },
    actions: {
        getRoute({commit}, list) {
            return new Promise(resolve => {
                commit('setRoutes', list)
                resolve(list)
            })
        },
        getShowRoute({commit}, list) {
            return new Promise(resolve => {
                commit('setShowRoutes', list)
                resolve(list)
            })
        }
    }
})

总结: 最后在理一下整个过程 - 存储权限路由数据,在进行跳转的时候进行筛选组合路由。其实筛选路由不一定要写在router.js,只要是你认为合适的地方都可以,在权限控制过程中最重要的是路由拦截。

模拟一下路由拦截的过程

假设login之后进入的/index,路由拦截的过程

/index - > token -> flag(true) ->获取路由权限 -> next('/index') -> 重新进入beforeEach-> token->flag(false) -> next() ->结束

按钮权限 - 操作(自定义指令)

按钮权限主要涉及的知识点就是全局自定义指令

写在main.js。或者单独js文件,main.js进行引入

import Vue from "vue"
import store from "../store"

//自定义指令 v-has进行权限判断
Vue.directive("has",{
  inserted : function (el,binding){
    //按钮权限
    const data = store.state.buttons;
    //按钮的值 <el-button v-has>aa</el-button>
    const value = binding.value; //a
    const hasPermissions = data.includes(value);
    if(!hasPermissions){
       //隐藏按钮
      el.style.display = "none";
      setTimeout(()=>{
        el.parentNode.removeChild(el)
      },0)
    }
  }
})

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • vue router权限管理实现不同角色显示不同路由

    目录 思路: 主要逻辑代码 全部页面代码 思路: login页面登录时 加上角色的标记,存储到本地缓存(localstorage) 路由js文件,meta属性加个是否可见(visiable true或false) home 基本导航栏页面逻辑,首先 可以获得到 所有一级菜单和角色标记 for 循环一级菜单 找出角色 所在的 角色数组(判断某个值在不在 数组中) 然后 所在的数组 visiable 改为true ,其他的改为false ui框架 是ant design of vue 主要逻辑代码

  • 前端配合后端实现Vue路由权限的方法实例

    目录 前言 实现思路 代码实现 登录 本地路由列表 生成路由 挂载路由 总结 前言 在开发管理后台时,都会存在多个角色登录,登录成功后,不同的角色会展示不同的菜单路由.这就是我们通常所说的动态路由权限,实现路由权限的方案有多种,比较常用的是由前端使用addRoutes(V3版本改成了addRoute)动态挂载路由和服务端返回可访问的路由菜单这两种.上一篇文章讲了纯前端实现路由权限,没看过的可以点击文章链接纯前端实现Vue路由权限.今天主要是基于后端返回路由菜单的基础上,实现路由权限功能. 实现思

  • Vue3纯前端实现Vue路由权限的方法详解

    目录 前言 RBAC模型 代码实现 登录 菜单信息 动态路由筛选 总结 前言 在开发管理后台时,都会存在多个角色登录,登录成功后,不同的角色会展示不同的菜单路由.这就是我们通常所说的动态路由权限,实现路由权限的方案有多种,比较常用的是由前端使用addRoutes(V3版本改成了addRoute)动态挂载路由和服务端返回可访问的路由菜单这两种.今天主要是从前端角度,实现路由权限的功能. RBAC模型 前端实现路由权限主要是基于RBAC模型. RBAC(Role-Based Access Contr

  • vue路由权限和按钮权限的实现示例

    目录 一 菜单路由权限 二 按钮权限的实现 一 菜单路由权限 1.1前端路由配置表 1.2后端数据返回 1.3 拿到数据后存到vuex 1.4 扁平化的目的是为了跳转路由时进行对比权限 //扁平化方法 flatten(data) { return data.reduce((arr,{name,id,resourceType,dimensionTypeCode,btnPermissions,path,children = [],}) => arr.concat([{name,id,resource

  • vue3使用vue-router及路由权限拦截方式

    目录 使用vue-router及路由权限拦截 vue3使用vue-router讲解 使用vue-router及路由权限拦截 vue3 使用 vue-router 的方式和 vue2 基本一样,只不过初始化路由时需要用到一些函数来定义而已,另外 vue-cli 工具本身在创建 vue3 项目时就可以根据提示来进行安装配置 vue-router , 所以本篇只是针对那些忘记安装的小伙伴. 第一步肯定是要先安装啦: npm install vue-router@4 接着我们在根目录 src 下创建 r

  • vue如何根据权限生成动态路由、导航栏

    目录 基本思路 相关代码 基本思路 1.创建vueRouter,用公共路由实例化 2.创建需要根据权限筛选的路由对象(在路由对象,添加必要的权限判断字段) 3.登录完成,由后端配合返回当前用户的权限集合 4.筛选出有权限的路由对象,利用vueRouter的addRoutes方法,生成完整路由 5.处理刷新页面导致vueRouter重新实例化导致路由对象不完善 (利用router.beforeEach导航守卫,,利用addRoutes()完善 路由对象 ) 6.侧边导航栏相关代码 相关代码 根据上

  • 手把手教学vue的路由权限问题

    目录 菜单权限 相关知识点了解 知识点集结 功能实现过程 按钮权限 - 操作(自定义指令) 总结 后台管理类系统大多都涉及权限管理,菜单权限,按钮权限. 菜单权限 菜单权限对应 - 路由.菜单权限 - 根据用户角色不同,路由文件动态配置. 相关知识点了解 vue-router vue-router是vue项目在进行开发过程中必不可少缺少的插件,目前vue2依赖的是vue-router3,vue3依赖的vue-router4 在进行权限控制之前一定要了解哪些路由需要权限哪些不需要 知识点集结 ro

  • 关于Vue的路由权限管理的示例代码

    前言 曾经在工作上对 vue 路由权限管理这方面有过研究,这几天又看到了几篇相关的文章,再加上昨天电面中又再一次提及到,就索性整理了一下自己的一些看法,希望对大家有帮助. 实现 大体上实现的思路很简单,先上图: 无非是将路由配置按用户类型分割为 用户路由 和 基本路由,不同的用户类型可能存在不同的 用户路由,具体依赖实际业务. 用户路由: 当前用户所特有的路由 基本路由:所有用户均可以访问的路由 实现控制的方式分两种: 通过vue-router addRoutes方法注入路由实现控制 通过vue

  • Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制

    思路 : 动态路由实现:在导航守卫中判断用户是否有用户信息, 通过调用接口,拿到后台根据用户角色生成的菜单树, 格式化菜单树结构信息并递归生成层级路由表并 使用Vuex保存,通过  router.addRoutes  动态挂载到  router  上,按钮级别的权限控制,则需使用自定义指令去实现. 实现: 导航守卫代码: router.beforeEach((to, from, next) => { NProgress.start() // start progress bar to.meta

  • vue 设置路由的登录权限的方法

    index.js 将需要登录权限的路由设置meta属性 meta:{requireAuth:true}, main.js 在main.js内直接写对路由的验证 router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requireAuth)){ // 判断该路由是否需要登录权限 if (sessionStorage.getItem("access_token")) {

  • Vue 配合eiement动态路由,权限验证的方法

    1.要实现动态路由,只需要在main.js中将所有路由表先规定好,如下 const routes=[ {path:'/login',component:login},/*登录*/ {path:'/home',component:home},/*首页*/ {path:'/monitor',component:monitor},/*实时监控*/ {path: "/orderQuery", component: orderQuery},/*电子围栏*/ {path: "/fence

  • vue路由权限校验功能的实现代码

    引言 做后台系统的时候,难免会有用户权限的判断.admin可以查看全部菜单,user只能查看部分菜单. 一开始接触这个需求的时候,完全是纯前端做的.在配置路由的时候,加一个roles的属性,通过判断用户的roles是否与路由的roles属性相匹配来作为显示隐藏的依据 { path: '/router', name: 'router', meta: { title: '标题', roles: ['admin','user'] }, component: index, children: [ { p

  • vue动态设置路由权限的主要思路

    之前看到网上有些动态设置路由的,但是跟目前的项目不是很匹配,就自己动手实现了一种.主要思路就是: 1.配置路由的时候绑定好id,可后端开发完成后,与后端同步id就行,这id唯一不变,根据此id可找到路由地址及icon. const routerArr = [ { path: '', name: '', component: () => import( /* webpackChunkName: "strategiesMaintain" */ '@/components/Layout

  • Vue实现两种路由权限控制方式

    目录 方式一:路由元信息(meta) 方式二:动态生成路由表(addRoutes) 路由权限控制常用于后台管理系统中,对不同业务人员能够访问的页面进行一个权限的限制. 对于无权限的页面可以跳转404页面或者提示无权限. 方式一:路由元信息(meta) 把所有页面都放在路由表中,只需要在访问的时候判断一下角色权限即可. vue-router 在构建路由时提供了元信息 meta 配置接口,我们可以在元信息中添加路由对应的权限,然后在路由守卫中检查相关权限,控制其路由跳转. 在 meta 属性里,将能

  • Vue路由权限控制解析

    前言 本人在公司主要负责中后台系统的开发,其中路由和权限校验算是非常重要且最为基本的一环.实际开发项目中,关于登录和路由权限的控制参照了vue-element-admin这个明星项目,并在此基础上基于业务进行了整合,接下来我会以这个项目为例,仔细地剖析整个路由和权限校验的过程,也算是对这个知识点的一些总结. 项目总体目录结构 进入今天主题之前,我们先来梳理下整个项目,src目录下的. api: 接口请求 assets: 静态资源 components: 通用组件 directive: 自定义指令

随机推荐