>>分享Web前端开发技术,并对孙卫琴的《精通Vue.js:Web前端开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 15028 个阅读者 刷新本主题
 * 贴子主题:  基于vue-element-admin 的权限管理 回复文章 点赞(0)  收藏  
作者:sunshine    发表时间:2021-04-21 06:14:47     消息  查看  搜索  好友  邮件  复制  引用

1.项目中要使用到权限管理及左侧菜单动态加载 基于此。

2.项目模板使用的是vue-admin-template

这个模板比较干净,只有框架的实现,要添加权限可以参考 github上vue-element-admin项目

首先路由页面router,有2个参数

export const constantRouterMap = [] 为初始路由参数,如登录 首页 404等共有页面 不需要权限控制的路由

export const asyncRouterMap = []为动态路由 登录成功后 在router.beforeEach中根据后端权限 加载不同路由 已展示不同的左侧菜单    
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'// progress bar style
import { getToken } from '@/utils/auth' // getToken from cookie

NProgress.configure({ showSpinner: false })// NProgress 页面导航

// 验证是否有权限
function hasPermission(roles, permissionRoles) {
  if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

const whiteList = ['/login', '/auth-redirect']//白名单

router.beforeEach((to, from, next) => {
  NProgress.start() // start progress bar
  if (getToken()) { // determine if there has token
    /* has token*/
    if (to.path === '/login') { //如果是进入登录页面 则不需要权限 直接进入
      next({ path: '/' })
      NProgress.done() // 页面导航结束
    } else {
      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(res => { // 拉取user_info
          store.dispatch('GenerateRoutes', res).then(() => { // 根据roles权限生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
          })
        }).catch((err) => {
          store.dispatch('FedLogOut').then(() => {
            Message.error(err || 'Verification failed, please login again')
            next({ path: '/' })
          })
        })
      } else {
        // next()
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        if (hasPermission(store.getters.perms, to.meta.perms)) {
          next()
        } else {
          next({ path: '/401', replace: true, query: { noGoBack: true }})
        }
        // 可删 ↑
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
      next()
    } else {
      next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
    }
  }
})

router.afterEach(() => {
  NProgress.done() // finish progress bar
})

  下面为加载路由代码    

import { asyncRouterMap, constantRouterMap } from '@/router'
// import store from '@/store'
/**
* 通过meta.role判断是否与当前用户权限匹配
* @param roles
* @param route
*/

function hasPermission(perms, route) {  //判断是否有权限
  if (route.meta && route.meta.perms) {
    return perms.some(perm => route.meta.perms.includes(perm))
  } else {
    return true
  }
}

/**
* 递归过滤异步路由表,返回符合用户角色权限的路由表
* @param routes asyncRouterMap
* @param roles
*/

function filterAsyncRouter(routes, perms) {  //过滤没有权限的列表 循环过滤 直到没有子路由
  const res = []
  routes.forEach(route => {
    const tmp = { ...route }
    if (hasPermission(perms, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRouter(tmp.children, perms)
      }
      res.push(tmp)
    }
  })
  return res
}

const permission = {
  state: {
    routers: constantRouterMap,
    addRouters: []
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {  //保存动态路由时 将静态路由和动态路由合并
      state.addRouters = routers
      state.routers = constantRouterMap.concat(routers)  
    }
  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const roles = data.roles
        const perms = data.perms
        let accessedRouters
        if (perms) {
          if (roles.includes(1)) {  //如果未admin角色 加载所有动态路由
            accessedRouters = asyncRouterMap
          } else {  //如果不是admin角色 则加载过滤后的动态路由
            accessedRouters = filterAsyncRouter(asyncRouterMap, perms)
          }
          commit('SET_ROUTERS', accessedRouters)  //保存路由
        }
        resolve()
      })
    }
  }
}

export default permission

  此时已经获得了想要的路由列表,定义一个获取路由的getter方法    

const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
userInfo: state => state.user.userInfo,
roles: state => state.user.roles,
perms: state => state.user.perms,
permission_routers: state => state.permission.routers,  //路由列表
addRouters: state => state.permission.addRouters
}
export default getters

  目录layout/sidebar/index.vue 这里是展示左侧列表的页面    

<template>
  <el-scrollbar wrap-class="scrollbar-wrapper">
    <el-menu
      :default-active="$route.path"
      :collapse="isCollapse"
      :background-color="variables.menuBg"
      :text-color="variables.menuText"
      :active-text-color="variables.menuActiveText"
      :collapse-transition="false"
      mode="vertical"
    >
      <sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/>   //加载这个路由就行
    </el-menu>
  </el-scrollbar>
</template>

<script>
import { mapGetters } from 'vuex'
import variables from '@/styles/variables.scss'
import SidebarItem from './SidebarItem'
import store from '@/store'

export default {
  components: { SidebarItem },
  created(){
    this.perms = JSON.stringify(this.$store.state.user.perms);
  },
  data(){
    return {
      perms: ''
    };
  },
  computed: {
    ...mapGetters([
      'permission_routers',
      'sidebar'
    ]),
    variables() {
      return variables
    },
    isCollapse() {
      return !this.sidebar.opened
    }
  },
  methods: {
      
  }
}
</script>

  最后 来个router页面    

{
    path: '/customerInfo',
    component: Layout,
    meta: { title: '客户信息管理', perms: ['customerPage'] },  //perms是后端返回的权限标识  写到这里可以使其所有子类都加上权限 也可以分别给子类添加
    children: [
      {
        path: '/customer',
        name: 'customer',  //name必须有 面包屑导航的显示
        component: () => import('@/views/page/customerInfo/index'),  //懒加载
        meta: { title: '客户信息管理', icon: 'customerInfo' } //title左侧菜单与面包屑导航显示文字 icon为左侧菜单图标
      },
      {
        path: '/customeraddressInfo',
        hidden: true,
        name: 'customeraddress',
        component: () => import('@/views/page/customerInfo/customeraddress'),
        meta: { title: '客户公司管理', icon: 'customerInfo' }
      }
    ]
  },
  {
    path: '/fleetGroup',
    component: Layout,
    meta: { title: '车队编组管理', perms: ['fleetgroupPage'] },
    children: [
      {
        path: '',
        name: 'fleet',
        component: () => import('@/views/page/fleetGroup/index'),
        meta: { title: '车队编组管理', icon: 'fleetGroup' }
      }
    ]
  },

----------------------------
原文链接:https://www.jianshu.com/p/4c2973f1d194

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2021-05-02 21:08:01 重新编辑]
  Java面向对象编程-->Lambda表达式
  JavaWeb开发-->Web运作原理(Ⅱ)
  JSP与Hibernate开发-->第一个helloapp应用
  Java网络编程-->对象的序列化与反序列化
  精通Spring-->组合(Composition)API
  Vue3开发-->通过Vuex进行状态管理
  大部分人都会做错的经典JS闭包面试题
  最新的Vue面试题大全含源码级回答,吊打面试官系列
  勇闯28个关卡学会HTML与HTML5基础
  好消息:《精通Vue.js:Web前端开发技术详解》出版了!
  Vue项目PWA化
  创建vue cli 插件
  Vue路由传递参数详细说明
  Thinking In Vue:vue指令的封装
  14个JavaScript优化建议
  jQuery 添加元素
  JavaScript的HTML DOM Input Search 对象
  HTML中插入脚本的用法
  JavaScript HTML DOM EventListener
  JavaScript 输出数据
  应该掌握的几个HTML标记语言(个人总结)
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。