vue 实现后台权限管理

1.权限管理思路 (权限(被分配)——》角色(被分配)---------》用户)  框架采用 vue-element-admin

2,我设计是角色中直接配置权限,看界面

  角色列表

 点击列表中  权限设置  打开的界面

  

权限设置中的树形菜单结构  id是唯一的。对应动态路由中  meta: {      permission: "对应树形菜单中唯一的id"    },  便于后期比对显示动态路由

{

    "data": [

        {

            "label": "测试模块",

            "id": "test",

            "children": [

                {

                    "label": "测试列表",

                    "id": "test-list",

                    "children": [

                        {

                            "label": "增加",

                            "id": "test-add"

                        },

                        {

                            "label": "删除",

                            "id": "test-delete"

                        },

                        {

                            "label": "修改",

                            "id": "test-update"

                        },

                        {

                            "label": "查看",

                            "id": "test-view"

                        }

                    ]

                }

            ]

        },
   ]
}

看一下动态路由 

 {
      path: 'test',
      component: () => import('@/views/modular/test/index'),
      name: 'test',
      alwaysShow: true,
      meta: {
        title: '测试模块',
        noCache: true,
        permission: "test",
      },
      children: [{
        path: 'test-list',
        component: () => import('@/views/modular/test/list'),
        name: 'test-list',
        meta: {
          title: '测试模块列表',
          noCache: true,
          permission: "test-list",
        },
      }]
    }

4.用户列表:

点击  角色设置  选中 角色列表中的测试

切换用户登陆   系统用户登陆 看到的菜单

 

二:代码编写

1)核心代码

vuex 中 peimission.js

import { asyncRoutes, constantRoutes } from '@/router'

/**
 * 通过meta.role判断是否与当前用户权限匹配
 * @param permission
 * @param route
 */
function hasPermission(permission, route) {
  if(route.meta && route.meta.permission) {
    return permission.indexOf(route.meta.permission) != -1
  } else {
    return false
  }
}

/**
 * 递归过滤异步路由表,返回符合用户角色权限的路由表
 * @param routes asyncRoutes
 * @param permission
 */
export function filterAsyncRoutes(routes, permission) { 
  const res = []

  routes.forEach(route => {
    const tmp = { ...route }

    if (tmp.children) {
      tmp.children = filterAsyncRoutes(tmp.children, permission)
      if (tmp.children && tmp.children.length > 0) {
        res.push(tmp)
      }
    } else {
      if (hasPermission(permission, tmp)) {
        res.push(tmp)
      }
    }
  })
  return res
}

const permission = {
  state: {
    routes: [],
    addRoutes: []
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.addRoutes = routes
      state.routes = constantRoutes.concat(routes)
    }
  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const { permission } = data
        let accessedRoutes;
        if(permission.indexOf("*") != -1) {
          accessedRoutes = asyncRoutes;
        } else {
          accessedRoutes = filterAsyncRoutes(asyncRoutes, permission)
        }
        commit('SET_ROUTES', accessedRoutes)
        resolve(accessedRoutes)
      })
    }
  }
}

export default permission

按钮权限检查代码 untis->permission.js

import store from '@/store'

/**
 * @param {Array} value
 * @returns {Boolean}
 * @example see @/views/permission/directive.vue
 */
export default function checkPermission (value) { 
  const permissions = store.getters && store.getters.permission
  if (permissions && permissions instanceof Array && permissions.includes("*")) return true
  if (value && value instanceof Array && value.length > 0) {
    const hasPermission = permissions.some(permission => {
      return value.includes(permission)
    })

    if (!hasPermission) return false
    return true
  } else if (value && typeof value == 'string') {
    return permissions.includes(value)
  } else {
    return false
  }
}

mian.js中

import Vue from 'vue'

import 'normalize.css/normalize.css' // A modern alternative to CSS resets

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n

import '@/styles/index.scss' // global css

import App from './App'
import store from './store'
import router from './router'

import '@/icons' // icon
import '@/permission' // permission control
import Avue from '@smallwei/avue';
import '@smallwei/avue/lib/index.css';

import '@/assets/css/index.scss' 
/**
 * If you don't want to use mock-server
 * you want to use MockJs for mock api
 * you can execute: mockXHR()
 *
 * Currently MockJs will be used in the production environment,
 * please remove it before going online ! ! !
 */
// if (process.env.NODE_ENV === 'production') {
//   const { mockXHR } = require('../mock')
//   mockXHR()
// }
Vue.prototype.checkPermission = require("@/utils/permission").default
// set ElementUI lang to EN
Vue.use(Avue);//使用AVUE
Vue.use(ElementUI)
// 如果想要中文版 element-ui,按如下方式声明
// Vue.use(ElementUI)



Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

mian.js 中 引入的这个文件  import '@/permission'   和main.js 平级

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' // get token from cookie

NProgress.configure({ showSpinner: false }) // NProgress Configuration
function hasPermission(permissions, permission) {
  if (!permission || permission == 'home' || permissions.indexOf("*") != -1) {
    return true
  }
  return permissions.indexOf(permission) != -1
}
const whiteList = ['/login','/auth-redirect'] // no redirect whitelist

router.beforeEach((to, from, next) => {

  NProgress.start()

  if (to.meta.title) {
    document.title = "cq-" + to.meta.title;
  } else {
    document.title = "cqadmin";
  }
 
  const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {     
      next({ path: '/' })
      NProgress.done()
    } else {    
      if (store.getters.permission.length === 0) {
        store.dispatch('user/getInfo').then(res => {
       
          const permission = res.results.permission
          if (res.results.is_admin) {
            res.results.permission.push('*')
          }
        
          if (permission.length) {
            store.dispatch('GenerateRoutes', res.results).then(accessRoutes => { // 根据后台查询出的菜单权限生成可访问的路由表          
              router.addRoutes(accessRoutes) // 动态添加可访问路由表            
              router.options.routes=store.getters.routers;   //很重要的一句
             
              next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 
            })
          } else {
            next({ path: '/401', replace: true, query: { noGoBack: true } })
          }
        }).catch(err => {
          store.dispatch('FedLogOut').then(() => {
            Message.error(err)
            next({ path: '/' })
          })
        })
      }else {
       // debugger
        //next()
        if (hasPermission(store.getters.permission, to.meta.permission)) { // 有权限
          next()
        } else { // 无权限
          next({ path: '/401', replace: true, query: { noGoBack: true } })
        }
      }

    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

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

参考:https://blog.csdn.net/qq_33705529/article/details/103582472?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase


版权声明:本文为xinxin_zhu原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。