vue-权限管理动态添加路由

224 阅读3分钟

前言

权限限制管理是在我们做后台管理系统项目的时候一个很常见的功能点,处理的方法也是有很多种,写这篇文章主要是为了记录方便以后查看,也是想分享一下自己的做法给大家参考,如果能帮到你们那是最好。 如果大家有更好的处理方法或思路还请不吝指教!

功能点分析

权限管理功能:为了管理不同账号用户的拥有权限,如管理员能看到所有页面、财务只能看到统计报表、财务的支出收入等页面、客服看到一些物流相关的页面等,这些不同角色他们负责的东西不同,因此要对他们分配不同权限去访问系统。而在开发中我们知道页面一般是通过路由去访问的,所以分配不同的权限相当于分配不同的路由。

业务梳理

graph TD
用户登录获取token --> 根据token获取相关权限 -->根据权限匹配路由-->通过路由渲染相应菜单-->进行访问

路由页面的基础配置

基础路由就是所有用户就可以访问的路由,在我们没有登录时总要有个页面给用户展示,如登录页面,所以我们要先配置一下基础的路由

创建router/index.js文件

import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [
    {
        path: "/",
        name: "",
        redirect: "/login",//重定向
    },
    {
    path: "/login",
    name: "Login",
    meta: {
      name: "登录",
    },
    component: (resolve) =>require(["@/views/Login/index"], resolve),
  },
]
const router = new VueRouter({
  routes,
});
export default router;

一、用户登录获取token

用户在登录页面输入账号密码成功登录之后,保存后端返回的token值到本地,方便后面用于获取菜单。因为逻辑在路由守卫中处理,所以在这里随意跳转一个路由(login除外)触发路由守卫

Login/login.vue

<template>
    <div>
        <div class="login">
            <label>账号:<label/>
            <input v-model="form.name" />
            <label>密码:<label/>
            <input v-model="form.password" />
        </div>
        <button @click="onLogin">登录< /button>
    <div/>
</template>
<script>
import axios from "axios"
export default {
    data(){
        form:{}
    },
    methods:{
        async onLogin(){
            //进行登录操作
            let res = await axios请求数据
            // 保存token到本地以及cookies
            localStorage.setItem('token',res.token)
            this.$router.push('/home')//跳转到首页,在路由守卫中根据token获取菜单权限
        }
    }
}
</script>

二、路由守卫逻辑分析

首先这里建议大家把获取的菜单数据保存在vuex中而非本地,毕竟本地上的数据是可以被修改的,安全起见保存在vuex上相对好一点。

  1. 先判断是否存在token,如果不存在则说明未登录强制返回登录页。
  2. 若存在token而vuex上没有菜单数据说明是刚登录完跳转页面或者是用户刷新页面(因为页面刷新会清除vuex上的数据),这时我们就要去调用接口获取数据了。
  3. 获取到数据之后将数据储存到vuex中。通过router.addRoutes()方法动态添加路由
  4. 完成后跳转到第一个路由进入页面

router/index.js

import store from './store'
import axios from "axios"
let requestNum = 0
const getMenuRouter =async ()=>{
    let res = await axios请求数据
    if(res.code==200){
    requestNum = 0
        //将菜单数据储存到vuex中
        store.commit('SET_MENU_LIST',res.data)
        let newRouter = []
        //一级菜单
        res.data.map((val,i)=>{
            newRouter.push({
                path: val.path,
                name:val.name,
                meta: {
                  name: val.title,
                },
                component: (resolve) =>require([`@/views/${val.name}/index`], resolve),
                children:[]
            })
            // 二级菜单
            if(val.children.length>0){
                val.children.map((subVal,j)=>{
                    newRouter[i].children.push({
                        path: subVal.path,
                        name:subVal.name,
                        meta: {
                          name: subVal.title,
                        },
                        component: (resolve) =>require([`@/views/${val.name}/${subVal.name}/index`], resolve),
                    })
                })
            }
        })
        router.addRoutes([
            {
                path: '/home', 
                name:'Home', 
                meta: { name: '首页', }, 
                component: (resolve) =>require([`@/views/Home/index`], resolve),
                children:newRouter
            }
        ])
        return res.data[0]
    }else{
        //若请求失败重新请求,超过十次不再请求
        if(requestNum>10){
            return false
        }
        requestNum++
        return await getMenuRouter()
    }
}
router.beforeEach(async (to, from, next) => {
    //没有token且去的不是登录页面则重定向到登录页面
    let token = localStorage.getItem('token')
    if(!token){
        if(to.path!='login'){
            return next('/login')
        }else{
            return next()
        }
    //存在token跟菜单数据,则为正常跳转
    }else if(token&&store.state.menuList.length>0){
        return next()
    //存在token而不存在菜单数据,页面刷新或者登录跳转,则需要请求接口获取菜单数据
    }else{
        let routerIndex =await getMenuRouter()
        if(!routerIndex){
            //这里提示接口异常,请联系管理员,后清除token跳回登录页
            localStorage.setItem('token','')
            return next('/login')
        }else{
            //请求到菜单数据添加到路由后跳转到权限的第一个页面
           return next(routerIndex.path)
        }
        
    }
    
})

三、vuex中储存菜单数据

store/index.js

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
      menuList:[]
  },
  getters: {},
  mutations: {
      SET_MENU_LIST:(state, data)=>{
          state.menuList = data
      }
  },
  actions: {},
  modules: {},
});

最后

关于权限管理动态添加路由的经验就分享到这里了,错误之处,请大佬指出!