>>分享Web前端开发技术,并对孙卫琴的《精通Vue.js:Web前端开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 22480 个阅读者 刷新本主题
 * 贴子主题:  基于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面向对象编程-->集合(上)
  JavaWeb开发-->Servlet技术详解(Ⅱ)
  JSP与Hibernate开发-->域对象在持久化层的四种状态
  Java网络编程-->通过JavaMail API收发邮件
  精通Spring-->Vue简介
  Vue3开发-->通过Vuex进行状态管理
  介绍axios的基本使用(vue中使用axios)
  Vue3.0 ref、reactive、toRef、toRefs、customRef的区别
  JS对树形数据的遍历和过滤,
  jQuery与AJAX的整合简介
  jQuery 删除元素
  jQuery 添加元素
  jQuery 选择器
  HTML DOM Radio 单选按钮对象
  JavaScript的Window 对象
  CSS 表单的用法
  HTML5 地理定位
  JavaScript prototype(原型对象)
  JavaScript HTML DOM EventListener
  JavaScript 正则表达式
  jQuery Mobile 事件
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


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