一、首先在main.js做路由守卫,不能先跳转路由页面,在页面中向后端获取路由配置文件

*相关补充:权限管理一般放到项目的最后时间来做,最开始路由配置信息前端都是写死,做权限管理的时候,需要将路由配置发给后端,让后端判断该显示哪些菜单,再返回给前端,不能前端判断,考虑到后端接口返回的值是可以被拦截修改的。*

main.js添加如下代码:

import store from "./store";
/**动态路由 */
const whiteList = ['Login', 'Index'];//默认可以跳转的路由。
let asyncRouterFlag = 0;
router.beforeEach(async(to, from, next) => {
    const token = localStorage.getItem('admin_systemToken');
    document.title = to.meta.title;  //设置标题
    if (whiteList.indexOf(to.name) > -1) {  //查询是否是默认可以跳转的路由
        if (to.path == '/login') {  //如果是去登录页面直接进入
            next();
        } else {
            if (!token) {   //没有登录,进入登录页
                next('/login');
            } else {
                if (!asyncRouterFlag) {    //进入非权限页面同时获取权限菜单。
                    asyncRouterFlag++
                    await store.dispatch('router/SetAsyncRouter')
                }
                next();
            }
        }
    }else{  //判断是否满足权限
        if(token){
            // 添加flag防止多次获取动态路由和栈溢出
            if (!asyncRouterFlag) {
                asyncRouterFlag++;
                //同步调用获取菜单方法
                await store.dispatch('router/SetAsyncRouter')   //发请求获取菜单,并将菜单设置到vuex中,
                const asyncRouters = store.getters['router/asyncRouters'];
                //循环后动态添加路由,addRoutes方法好像不能用了
                asyncRouters.map(asyncRouter => {
                    router.addRoute(asyncRouter)      
                })
                next({ ...to, replace: true })
            } else {
                next()
            }
        }else{
            next({
                path: '/login',
                // query: {
                //     redirect: document.location.hash
                // }
            })
        }
    }
})

二、获取路由配置文件。路由配置文件基本上跟后台的菜单结构都差不多,所以获取了路由配置文件的时候,就不需要再获取菜单了。那么路由配置文件最好是写在vuex中

1.新建一个vuex模块,并使用。

store/index.js:

import Vue from 'vue'
import Vuex from 'vuex'
import router from './router/index.js'
Vue.use(Vuex)


export default new Vuex.Store({
    state: {

    },
    mutations: {

    },
    actions: {},
    modules: {
        router
    }
})

2.路由配置文件相关处理。

store/router/index.js:


export default {
    namespaced: true,
    state: {
        //动态路由配置
        asyncRouters:[]
    },
    mutations: {
        // 设置动态路由
        setAsyncRouter(state, asyncRouters) {
            state.asyncRouters = asyncRouters
        }
    },
    actions: {
        //获取菜单
        async SetAsyncRouter({ commit }) {
            //获取菜单的路由配置,并配置
            var list=[
            {
                path: "#",
                component: () =>import("@/views/layout/index.vue"),
                meta: {
                    icon: 'el-icon-message'
                },
                children: [{
                    path: "/userManage/userList",
                    name: "userManageUserList",
                    component: (resolve) => require(['@/views/userManage/userList/index.vue'], resolve),
                    meta: {
                        title: "用户列表",
                        icon: 'el-icon-position'
                    }
                }]
            },
            {
                path: "#",
                component: () =>import("@/views/layout/index.vue"),
                meta: {
                    icon: 'el-icon-message'
                },
                children: [{
                    path: "/systemConfig/adminUser",
                    name: "systemConfigAdminUser",
                    component: (resolve) => require(['@/views/systemConfig/adminUser/index.vue'], resolve),
                    meta: {
                        title: "后台用户",
                        icon: 'el-icon-position'
                    }
                }]
            },
            {
                path: "#",
                component: () =>import("@/views/layout/index.vue"),
                meta: {
                    icon: 'el-icon-message'
                },
                children: [{
                    path: "/systemConfig/roleManage",
                    name: "systemConfigRoleManage",
                    component: (resolve) => require(['@/views/systemConfig/roleManage/index.vue'], resolve),
                    meta: {
                        title: "角色管理",
                        icon: 'el-icon-position'
                    }
                }]
            },
            {
                path: "#",
                component: () =>import("@/views/layout/index.vue"),
                meta: {
                    icon: 'el-icon-message'
                },
                children: [{
                    path: "/systemConfig/otherConfig",
                    name: "systemConfigOtherConfig",
                    component: (resolve) => require(['@/views/systemConfig/otherConfig/index.vue'], resolve),
                    meta: {
                        title: "其他参数配置",
                        icon: 'el-icon-position'
                    }
                }]
            }];
            //添加404页面,这个只能在路由最后添加。
            list.push({
                path: '/404',
                name: '404',
                hidden: true,
                meta: {
                    title: '迷路了*。*',
                },
                component: () =>import("@/views/error/index.vue"),
            },{
                path: "*",
                redirect: "/404"
            },);
            commit('setAsyncRouter',list);
        }
    },
    getters: {
        //获取动态路由
        asyncRouters(state) {
            return state.asyncRouters
        },
  }
}

说明:list的数据等于后端返回给前端的数据,大家使用的时候需要调后端api获取,我这里直接写死,考虑到这里还会有一些判断,为了让大家更清楚看懂。

注意:

1.404页面必须放到最后添加,不然会出现奇怪的问题。

2.main.js文件使用了router.beforeEach,其他任何文件就不能再使用了,不能会进行双重判断,出现一些异常问题。

三、静态路由配置文件(参考)。

const routes = [{
        path: "/",
        redirect: '/index'
    },
    {
        path: "/login",
        name: "Login",
        // component: (resolve) => require(['@/views/login/index.vue'], resolve),
        component: () =>import("@/views/login/index.vue"),
        meta: {
            title: "登录"
        }
    },
    {
        path: "/index",
        component: Layout,
        children: [{
            path: "/index",
            name: "Index",
            component: (resolve) => require(['@/views/index/Index.vue'], resolve),
            meta: {
                title: "首页",
                icon: 'el-icon-s-home'
            }
        }]
    },
];

四、登录后需要干什么(参考)。

登录后,代码:

        //登录
        login({username,password}){
            let res = this.$api.login({
                account:username,
                password:password
            }).then(res=>{
                if (res.code === 200) {
                    this.$message({type: 'success',message: res.msg});
                    localStorage.setItem('admin_systemToken', res.data.api_key);
                    this.$router.push('/');
                } else {
                    this.$message({type: 'error',message: res.msg});
                }
            }).catch(err=>{
                console.log(err);
            });
        }

存储自己的token。

五、token过期,退出登录切换账号我们需要清除已经注册的路由,防止其他用户获得到已经注册好了的路由。

1.退出登录,跳转登录页面,并进行一次刷新操作:

router.replace({path: '/login'});
    window.location.reload();

token过期时的请求拦截,如何刷新?

2.考虑到请求有可能是多个,就有可能造成多个无限刷新操作,这里需要判断一下当前页面是否在登录页面。

代码:注意:我的判断代码还没有写哈,根据自己的情况来判断重复跳转,重复刷新。

service.interceptors.response.use((res) => {
  console.log(res, '我是拦截')
  // if(res.)
  nprogress.done()
  return res.data
}, err => {
  let status = err.response.status
  if (err.response && err.response.status) {
    console.log(err.response)
    if (status == 401) {
      Message.error('登录失效,请刷新后重试')
      router.replace({path: '/login'});
        window.location.reload();
    }
  }
  return Promise.reject(err.response)
})

3.注意检查登录页面是否有请求会出现token过期的状态码,如果有,跟后端沟通给其他的状态码,防止登录页无限刷新。

Logo

前往低代码交流专区

更多推荐