vue2.x使用beforeRouteEnter路由钩子进行鉴权

前言

第一次在掘金发文章,不对的地方还请你们多多指点。后台管理系统,其中比较重要的一点就是权限控制。最近一年一直在使用vue全家桶进行后台管理系统的开发,说说个人一点心得。vue

基础页面结构

后台管理系统主要分为一个登陆页和主页面,主页面里面的路由是须要进行鉴权的,而权限数据通常都是登陆接口返回的。下面是一个常见的路由git

export default new Router({
    routes: [
        { path: "/", name: "home", component: Home ,redirect: '/index',
            children: [ /*这里配置页面路由*/ ]
        },
        { path: "/login",name: "login",component: Login },
        { path: "*",redirect: '/'},//其余错误的url重定向到主页
    ]
});

复制代码

登陆接口返回的权限数据不能直接存储到vuex中,由于在主页面(Home.vue)刷新以后数据就没了,固然了有持久化存储的方案(先不讨论),主页须要的菜单数据,若是是和路由数据差异很大,能够写死,可是不影响咱们使用beforeRouteEnter路由钩子鉴权。github

改写路由数据

若是想实现路由数据复用到菜单,咱们能够在router.js中将路由数据配好,可是不初始化:vue-router

const routes= [
    {
        path: '/',name: 'home',component: () => import('~/Home'),//按需加载
        redirect: '/menu1',children: [/*页面的路由,具体请看文末完整demo*/]
    },
    { path: '/login', name: 'login', component: () => import('~/Login') },
    { path: "*", redirect: '/login' },
];
export default routes;
复制代码

而后在main.js中初始化路由数据vuex

import Router from "vue-router";
import routes from "./router";//引入路由数据
Vue.use(Router);
const router = new Router({routes});//实例化路由对象
复制代码

beforeRouteEnter路由钩子鉴权

home.vue页面的beforeRouteEnter路由钩子触发时机就是第一次进入home.vue页面的时候,可是在这个页面中点击其余菜单不会触发,咱们也只须要在第一次进入的时候对菜单进行初始化。bash

咱们须要在Home.vue中利用beforeRouteEnter路由钩子生成权限菜单,并存储权限数据到vuex中,首先在Login.vue页面将登陆返回的权限数据存储到本地localStorage或者sessionStorage,而后 Home.vue中引入路由数据,下面代码中routes就是引入的路由数据cookie

beforeRouteEnter (to, from, next) {
    const permission = localStorage.getItem('permission');//也可也使用sessionStorage,看实际状况须要
    if(!permission){//没有权限就直接退出
        next({ name: "login", replace: true });
    }
    const rightArr = JSON.parse(permission),
    //路由数据过滤无权限的页面并转为菜单数据
        transMenu = (arr, parebtPath = '/') => 
            arr.filter(item => rightArr.includes(item.meta.code)).map(item => ({
                path: parebtPath + item.path,//路由对应的全路径
                name: item.meta.name,//路由对应的中文名称
                icon: item.meta.icon,//路由对应的icon图标
                code: item.meta.code,//路由对应的权限code
                children: item.children ? transMenu(item.children, `${parebtPath}${item.path}/`) : null,
            })),
        menu = transMenu(routes[0].children);
    if(!menu.length){//没有菜单权限
        next({ name: "login", replace: true });
    }
    next(vm => {
        if(!rightArr.includes(to.meta.code)){//当前url没权限就跳转到第一个菜单
            vm.$router.replace(menu[0].path);
        }
        vm.menuData = menu;
        vm.$store.commit("setPermission", rightArr);
    })
}
复制代码

补充说明

  1. beforeRouteEnter钩子鉴权是彻底可行的,登陆以后没权限的菜单入口不会显示,即便你在url里面输入没权限的路由,刷新页面依然会触发beforeRouteEntersession

  2. 也能够用beforeEach这个路由钩子进行鉴权,可是我的不倾向于这个办法,每次跳转都检查一下有点浪费,使用主页面的beforeRouteEnter钩子既完成了鉴权,也实现了权限和token的持久化存储。ui

  3. 我很是推荐你们使用localStoragesessionStoragecookie仍然存在的价值就是主域名相同的时候能够共享。url

  4. 路由的meta对象还能够添加其余的数据,好比说这个路由不生成菜单,就能够在这里面加一个flag, 而后就是不须要鉴权的菜单能够直接将code设置固定值或者为空,看本身定义。

  5. 代码里面有一点缺陷就是菜单生成的时候,若是有子孙菜单项的权限,可是没有父级菜单权限,就不会生成菜单数据。解决办法也很简单,将arr.filter(item => rightArr.includes(item.meta.code))这一段代码改成递归判断子孙节点的权限便可

最后

完整demo的地址:github.com/gongshun/vu…,有什么问题或者代码有啥疑问,欢迎你们评论

相关文章
相关标签/搜索