Vue学习篇1_用户权限控制_登录的用户从后端获取角色信息role,前端动态展示侧边导航栏、不同资源

一、写在前面

关于前端的权限控制,常见的体现用处:

  • 不同的用户左边展示的菜单栏不太一样
  • 不同的用户根据具有的角色不同实现显示不同的资源及控件

下面具体的展示的实现


二、具体实现

2.1动态菜单栏

1.新建store/permission.js文件,配合router.js来实现功能

大致原理:根据登录用户的role来 在 原来 静态路由constantRouters 的基础上 将待添加路由 addRouters 拼接上

// store/permission.js

// 0. 导入router.js下的静态路由、动态获取的路由映射
import {
    
     asyncRouterMap, constantRouters } from '@/router';

// 1. 判断角色对应的路由映射权限
function hasPermission(roles, route) {
    
    
  if (route.meta && route.meta.role) {
    
    
    var index = route.meta.role.indexOf(roles)
    if(index === -1)
    return false
    return true
    
    //return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    
    
    return true
  }
}

// 2. permission定义
const permission = {
    
    
  state: {
    
    
    routers: constantRouters,
    addRouters: []
  },
  mutations: {
    
    
  // 3. 将动态获取的路由 拼接到 静态路由映射列表 功能
    SET_ROUTERS: (state, routers) => {
    
    
      state.addRouters = routers;
      state.routers = constantRouters.concat(routers);
    }
  },
  // 4. 行为方法,根据role调用 3 的功能
  actions: {
    
    
    GenerateRoutes({
    
     commit }, data) {
    
    
      return new Promise(resolve => {
    
    
        const {
    
     roles } = data;
        const accessedRouters = asyncRouterMap.filter(v => {
    
    
          if (roles.indexOf('admin') >= 0) return true;
          //5.  调用第1部的方法
          if (hasPermission(roles, v)) {
    
    
            if (v.children && v.children.length > 0) {
    
    
              v.children = v.children.filter(child => {
    
    
                if (hasPermission(roles, child)) {
    
    
                  return child
                }
                return false;
              });
              return v
            } else {
    
    
              return v
            }
          }
          return false;
        });
        // 6. 使用accessRouters接收 该角色对应的列表 映射
        commit('SET_ROUTERS', accessedRouters);
        resolve();
      })
    }
  }
};

export default permission;


2.在store/index.js下注册permission

在这里插入图片描述

3.在store/getter.js中定义addRouters

在这里插入图片描述

4.修改router/index.js,将初始化路由 和 动态获取的路由分开

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'

/**
 * Note: sub-menu only appear when route children.length >= 1
 * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
 *
 * hidden: true                   if set true, item will not show in the sidebar(default is false)
 * alwaysShow: true               if set true, will always show the root menu
 *                                if not set alwaysShow, when item has more than one children route,
 *                                it will becomes nested mode, otherwise not show the root menu
 * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
 * name:'router-name'             the name is used by <keep-alive> (must set!!!)
 * meta : {
    roles: ['admin','editor']    control the page roles (you can set multiple roles)
    title: 'title'               the name show in sidebar and breadcrumb (recommend set)
    icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
  }
 */

/**
 * constantRoutes
 * a base page that does not have permission requirements
 * all roles can be accessed
 */
// 1. 任何登录角色都能看到的静态路由
export const constantRouters = [
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    
    
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
    
    
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: {
    
     title: '首页', icon: 'dashboard' }
    }]
  },
]
const createRouter = () => new Router({
    
    
  // mode: 'history', // require service support
  scrollBehavior: () => ({
    
     y: 0 }),
  routes: constantRouters
})

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
    
    
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

// 2. 根据角色动态显示的路由
export const asyncRouterMap = [
  {
    
    
    path: '/declaration-form',
    component: Layout,
    children: [{
    
    
      path: 'declaration-form',
      name: 'DeclarationForm',
      //declaration-form/index
      component: () => import('@/views/declaration-form/index'),
      meta: {
    
      role: ['基层教学组织负责人','系统管理员' ], title: '申报表填报', icon: 'form' }
    }]
  },

  {
    
    
    path: '/approval-page',
    component: Layout,
    children: [{
    
    
      path: 'approval-page',
      name: 'ApprovalPage',
      component: () => import('@/views/approval-page/index'),
      meta: {
    
     role: ['基层教学组织负责人' ,'系统管理员','校级管理员','院级管理员','评审专家'], title: '申报表审核', icon: 'approval' }
    }]
  },

  {
    
    
    path: '/detail-page',
    component: Layout,
    children: [{
    
    
      path: 'detail-page',
      name: 'detailPage',
      component: () => import('@/views/detail-page/index'),
      meta: {
    
     role: ['基层教学组织负责人' ,'系统管理员','校级管理员','院级管理员','评审专家'], title: '申报表详情' },
      hidden: true
    }]
  },

  {
    
    
    path: '/user-management',
    component: Layout,
    children: [{
    
    
      path: 'user-management',
      name: 'UserManagement',
      component: () => import('@/views/user-management/index'),
      meta: {
    
     role: ['系统管理员','校级管理员','院级管理员'], title: '用户管理', icon: 'user' }
    }]
  },

  {
    
    
    path: '/dispatch-form',
    component: Layout,
    children: [{
    
    
      path: 'dispatch-form',
      name: 'DispatchForm',
      component: () => import('@/views/dispatch-form/index'),
      meta: {
    
     role: ['系统管理员','校级管理员','院级管理员'], title: '分配管理', icon: 'dispatch' }
    }]
  },

  {
    
    
    path: '/data-analysis',
    component: Layout,
    children: [{
    
    
      path: 'data-analysis',
      name: 'DataAnalysis',
      component: () => import('@/views/data-analysis/index'),
      meta: {
    
     title: '数据分析', icon: 'pie' }
    }]
  },

  {
    
    
    path: '/information',
    component: Layout,
    meta: {
    
     role: ['教师'], title: '信息填报', icon: 'user-info' },
    children: [{
    
    
      path: 'teacher-info',
      name: 'TeacherInfo',
      component: () => import('@/views/information/teacher-info'),
      meta: {
    
     title: '个人概况' }
    }, {
    
    
      path: 'research-info',
      name: 'ResearchInfo',
      component: () => import('@/views/information/research-info'),
      meta: {
    
     title: '教学研究内容' }
    }, {
    
    
      path: 'competition-info',
      name: 'CompetitionInfo',
      component: () => import('@/views/information/competition-info'),
      meta: {
    
     title: '教学竞赛内容' }
    }]
  },

  // 404 page must be placed at the end !!!
  {
    
     path: '*', redirect: '/404', hidden: true }
]



5.修改layout/Sidebar/index.vue,修改配置store下的路由显示,将通过调用store/permission方法动态获取的路由映射 拼接到 原始的默认路由映射中

在这里插入图片描述

6.在src/permission.js中拉去用户信息的方法中,获取role之后,调用方法根据role生成路由列表

在这里插入图片描述

在这里插入图片描述

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
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({
    
     showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async (to, from, next) => {
    
    
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    
    
    if (to.path === '/login') {
    
    
      // if is logged in, redirect to the home page
      next({
    
     path: '/' })
      NProgress.done()
    } else {
    
    
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
    
    
        next()
      } else {
    
    
        if (store.getters.role.length === 0) {
    
    
          // get user info
          await store.dispatch('user/getInfo').then(res => {
    
    
            const roles = res.role;
            store.dispatch('GenerateRoutes', {
    
     roles }).then(() => {
    
    
              //console.log(store.getters.addRoutes)
              router.addRoutes(store.getters.addRoutes.permission.addRouters)
              next({
    
     ...to, replace: true })
            }
            )
          }
          ).catch(error => {
    
    
            console.log(error)
          });
        }
        else {
    
    
          // remove token and go to login page to re-login
          // await store.dispatch('user/resetToken')
          // Message.error(error || 'Has Error')
          // next(`/login?redirect=${to.path}`)
          // NProgress.done()
          next()
        }
      }
    }
  } 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()
})

然后就大致完成了

2.2动态资源显示

这个跟传统的开发模式如 springboot + shiro + Thymeleaf模板引擎实现权限控制类似

那种是Thymeleaf整合shiro之后直接在 jsp页面加 shiro-xxx标签即可

现在的前端控制直接在全部在vue中实现,大致的思路是:

  1. 首先在main.js中定义 权限制令权限检查方法,也就是自定义v-has标签,检查权限roles数组中无指定权限角色,有就显示。
  2. 定义roles数组,存储当前用户角色,方便动态添加权限角色。
  3. 定义获取当前role,设置权限数组的方法,在资源内部使用v-has="roles"完成角色资源显示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_24654501/article/details/114410555