vue系统权限(动态加载路由方式)

目录

1、注册vue-router

2、声明 默认路由 和权限路由

3、用vuex实现全局登录、退出登录等方法

4、用vuex模块单独写权限路由的判断

5、监听路由跳转实现动态加载权限菜单


需要用到动态加载路由,router.addRouters()来动态的挂载路由,接下来我们来一步一步分解步骤。

1、注册vue-router

创建 router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './router'

// hack router push callback
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location, onResolve, onReject) {
  if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
  return originalPush.call(this, location).catch(err => err)
}

Vue.use(VueRouter)

export default routes

2、声明 默认路由 和权限路由

创建router/router.js,生成全局路由变量


import VueRouter from 'vue-router'

// 路由基础表
export const routes = [
    // 起始页
    {
        path: '/',
        name: 'index',
        component: () => import('@/views/index/')
    },
    // 首页
    {
        path: '/home',
        name: 'home',
        component: () => import('@/views/home/')
    },
    // 登录页
    {
        path: '/login',
        name: 'login',
        component: () => import('@/views/login/')
    },
    {
        path: '/error',
        component: () => import('../views/404/'),
        name: 404
    },
    {
        path: "*", // 此处需特别注意置于最底部
        redirect: "/error"
    }
]

// 路由动态菜单 (需权限调控)
export const asyncRouteMap = [
    // 报表页
    {
        path: '/report',
        name: 'report',
        component: () => import('@/views/report/')
    },
    // 报表页
    {
        path: '/report2',
        name: 'report2',
        component: () => import('@/views/report2/')
    },
]


// 因为可以动态的挂载路由,但是不能动态删除路由。所以才考略到,
// 在需要动态清空动态挂载路由的话,直接将一个新的路由对象赋值给旧的路由对象,这样就可以达到动态清除的工作
const createRouter = () => new VueRouter({routes})
  
  
const router = createRouter()
  
// 调用该方法动态清除动态挂载路由
export function resetRouter () {
    const newRouter = createRouter()
    router.matcher = newRouter.matcher // reset router
}
  
 export default router

3、用vuex实现全局登录、退出登录等方法

创建 store/index.js,里面装载 用户登录 、获取权限、 退出登录清空权限、存放token和权限菜单等全局变量和方法。

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

Vue.use(Vuex);

import { resetRouter } from '../router/router' 
import router from '../router/'

import { userInfo } from '@/api/login'

// 引入权限模块
import permission from './permission'

export default new Vuex.Store({
    //所有的数据都放在state中
    state: {
        roles: [],
        token: localStorage.getItem('token') || ''
    },

    //操作数据,唯一的通道是mutations
    mutations: {
        // 将获取到的token存储到本地
        SET_TOKEN (state, token) {
            state.token = token
            localStorage.setItem('token', state.token)
        },
        // 将获取到的roles粗出到本地
        SET_ROLES (state, roles) {
            state.roles = roles
            localStorage.setItem('roles', JSON.stringify(state.roles))
        }
    },

    // 可以来做异步操作,然后提交给mutations,而后再对state(数据)进行操作
    actions: {
        // 用户登录
        userLogin ({ commit }, data) {

            // 返回一个异步回调,promise
            return new Promise(async (resolve, reject) => {
                // 调用登录接口 
                let res = await userInfo({password: data.password, username: data.username})
                // 如果登录成功
                if (res.status === 200) {
                    // 调用mutations中的方法,将token存储到本地中
                    commit('SET_TOKEN', res.data.token)
                    resolve(res.data)
                } else {
                    reject(res.message)
                }
                
            })
        },
        // 根据用户的token获取用户的个人信息,里面包含了权限信息
        getUserInfo ({ state, commit }) {
            // 返回一个异步回调,promise
          return new Promise((resolve, reject) => {
            // 获取有无缓存权限菜单
            let roles = localStorage.getItem('roles') ? JSON.parse(localStorage.getItem('roles')) : []
            // 如果已有权限菜单则不必再去请求接口
            if (roles.length > 0) {
                commit('SET_ROLES', roles)
            // 调用用户权限接口方法获取数据 (看自己项目,有的在登录接口则返回,有的在用户信息接口)
            // 将获取到的信息放到数组中存储 (这里自定义)
            } else {
                let data = ['report']
                commit('SET_ROLES', data)
            }
            resolve(state.roles)
          })
        },
        // 退出登录
        userLogout ({ commit }) {
            // 清空权限菜单
            commit('SET_ROLES', [])
            // 清空token
            commit('SET_TOKEN', '')
            // 清除路由
            resetRouter()
            // 跳转到登录菜单
            router.push({path: '/login'})
        }
    },
    // vuex的计算属性
    getters: {
        // 将用户数据放到计算属性中,一旦数据发生变化,可以重新计算
        roles (state) {
            return state.roles
        },
        token (state) {
            return state.token
        }
    },
    // 模块
    modules: {
        permission
    }
})

4、用vuex模块单独写权限路由的判断

创建 store/permission.js,编写 GenerateRoutes 方法判断获取有权限的路由, hasPerMission 函数用于判断权限主要核心函数。

GenerateRoutes 方法由 utils/global.js 调用,传进来判断权限的数组格式为自定义的 ['report'] 之类,按自己需求去改写,权限的获取在 store/index 的getUserInfo函数。

// 引入基础路由
import { routes, asyncRouteMap } from '../router/router' 


// 用来筛选后端返回来的权限数据,和权限路由中的meta里面的数据匹配,匹配成功返回true,失败为false

function hasPerMission (roles, route) {
  if (route && route.name) {
    return roles.indexOf(route.name) > -1
  } else {
    return true
  }
}

const permission = {
    state: {
      routers: routes,
      addRouters: []
    },
    mutations: {
      // 将匹配成功的权限路由拼接到公共路由中
      SET_ROUTERS (state, routers) {
        state.addRouters = routers
        state.routers = routes.concat(routers)
      }
    },
    actions: {
      // 对后台返回来的权限和动态路由权限匹配
      GenerateRoutes ({ commit }, data) {
  
          // 返回一个异步回调promise
        return new Promise((resolve, reject) => {
  
          // 遍历权限路由数组
          const accessedRoutes = asyncRouteMap.filter(v => {
  
            // 之后就是调用hasPerMission函数对象权限动态路由和后台返回的用户权限进行严格匹配
            if (hasPerMission(data, v)) {
              
              // 判断是否有权限路由是否有子路由,有子路由继续遍历 (只做到二级)
              if (v.children && v.children.length > 0) {
                v.children = v.children.filter(child => {
  
                  // 对权限子路由和后台返回的用户权限数据,在进行匹配,匹配成功返回
                  if (hasPerMission(data, child)) {
                    return child
                  }
                  
                  // 失败返回false
                  return false
                })
  
                  // 并且要把权限的父路由返回来,不光要把权限子路由返回,无论权限子路有还是没有,都应该把权限父路由返回来
                return v
              } else {
      
                  // 权限父路由匹配成功返回
                return v
              }
            }
      
             // 如果每一个判断都没有进,说明该用户没有任何权限,返回false
            return false
          })

          commit('SET_ROUTERS', accessedRoutes)
          resolve()
        })
      }
    },
    getters: {
      // 只要权限路由数组发生变化就重新计算
      addRouters (state) {
        return state.addRouters
      }
    }
  }
  export default permission

5、监听路由跳转实现动态加载权限菜单

创建 utils/global,监听路由的跳转后,

判断是否 有token,没有则跳向登录页,

如果有token,则进行用户权限获取 (在store/index下的getUserInfo函数),

获取完权限进入 store/permission的GenerateRoutes函数 进行获取符合条件的路由,

再通过addRoutes方法加载路由

// 先把路由和vuex引进来使用
import router from '../router'
import store from '../store'

const whiteList = ['/login'] // 不重定向白名单

router.beforeEach((to, from, next) => {
  if (store.getters.token) {
    // 判断如果是去登陆页面的话,返回主页,不让他返回登录页
    if (to.path === '/login') {
      next({ path: '/home' })
    } else {
      // 否则判断一下用户的个人信息是否已经拉取完毕
      if (store.getters.roles.length === 0) {
        // 拉取用户个人信息
        store.dispatch('getUserInfo').then(data => {
          // 拿到用户后台返回的权限数据
          const roles = data
          // 调用 permission.js方法中的GenerateRoutes方法,将后台返回的用户的权限数据,传递回去进行筛选处理
          store.dispatch('GenerateRoutes', roles).then(() => { // 生成可访问的路由表
            // 将筛选的权限路由数组动态挂载
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes添加完成
          })
        }).catch(error => {
          // 验证失败重新登陆
          next({ path: '/login' })
        })
      } else {
        next() // 当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的页面会自动进入404页面
      }
    }
  } else {
    // 如果已经去了登陆页面了,就不需要再next到登陆页面了,这就是重定向白名单
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
    }
  }
})

github地址:https://github.com/banxia1609/framehttps://github.com/banxia1609/frame

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值