vue如何实现路由权限控制

本文介绍两种实现路由权限控制的方法:一是通过路由拦截实现;二是利用Vue-router动态注入路由。前者适用于固定路由表,后者则适用于动态生成路由表的情况,并提供了解决路由累积问题的方案。

前言

在实际的开发过程中,我们通常会涉及到权限的问题,不同的用户进来只能看到他对应的菜单权限,页面上的菜单渲染是比较好实现的,这里就不多提,唯一比较难的就是路由的权限控制。

解决思路

目前大概有两种思路可以实现路由的权限控制:

1.通过router.beforeEach() 路由拦截的方式实现。

2.通过vue-router 官方提供的addRoutes()来进行动态路由注入,注意 该方法只有vue-router的版本 >= 2.2才有效。

我们可以来看这两种方式是如何实现的:

解决方案

路由拦截的方式

这种方式依赖于我们项目的路由表都是事先配置好的,假设我们的路由表有:

const router = new Router({
  routes: [{
        path: '/',
        redirect: '/index1'
    }, {
        path: '/index1',
        name: 'Index1',
        component: Index1
    }, {
        path: '/index2',
        name: 'Index2',
        component: Index2
    }, {
        path: '/index3',
        name: 'Index3',
        component: Index3
    }]
})

export default router;

在 router/index 中,通过router.beforeEach() 路由拦截去进行权限判断:

router.beforeEach((to, from, next) => {
    //to: 从哪个路由来
    //from: 去哪个路由
    //next:是一个方法,使用路由拦截,必须在后面添加next(),否则路由无法跳转

    //假设我们从后台获取的权限为:
    const list = ['index1', 'index2'];

    //如果没有匹配到,证明没有权限
    if(list.indexOf(to.name) === -1) {
        //next('/login');

        ... //或者执行其他操作
    }

    //路由拦截可根据项目返回的权限自行调整,这里只是做了一个简单的例子
})

到这里,我们就已经完成了第一种方案的路由权限控制,不过个人感觉算是比较low的一种方案,接下来,我们来重点看看第二种方案

动态注入路由

这种方式我们只需要配置静态的路由表,比如登录、注册页,其他路由通过动态注入:

const router = new Router({
  routes: [{
        path: '/',
        redirect: '/login'
    }, {
        path: '/login',
        name: 'login',
        component: Login
    }]
})

export default router;

假设我们在 登录 的时候,后端返回的权限列表如下:

//leaf: 是我们用来判断是否唯一的
//component:一般来说后端返回给我们的就是一个路径而已,所以我们需要自行的去加载组件
export const routers = [{
    path: '/main',
    name: 'main',
    leaf: false,
    component: 'pages/main',
    children: [{
        path: '/main/index1',
        name: 'index1',
        component: 'pages/index1',
        leaf: true
    }, {
        path: '/main/index2',
        name: 'index2',
        component: 'pages/index2',
        leaf: true
    }, {
        path: '/main/index3',
        name: 'index3',
        component: 'pages/index3',
        leaf: true
    }, {
        path: '/main/index4',
        name: 'index4',
        component: 'pages/index4',
        leaf: true
    }]
}, {
    path: '*',
    component: 'pages/noFind',
    leaf: true
}]

可以写个方法去再次过滤返回回来的路由列表

/**
 * @param routers 初始数据,为数组格式,一般来说是个空数组
 * @param data 后端返回的路由列表数据
 */
function generaMenu(routers, data) {
  data.forEach((item)=>{
    let menu = Object.assign({},item);
    menu.component = import(`@/${menu.component}.vue`);
    if(!item.leaf) {
      menu.children = [];
      generaMenu(menu.children,item.children);
        menu.redirect = menu.children[0].path; //如果需要重定向的话,可以根据自己的需求进行选择
    }
    routers.push(menu);
  })
}

注意 如果有用到404的路由话,需要把404这个路由放到整个路由表的最后一个,否则,因为一开始我们是没有对应的动态路由,默认就跳转到了404页面了,所以静态路由表不配置404路由,与动态路由一起注入到路由表中。

这样我们最终就得到了符合路由规则的路由表了。然后通过 addRoutes() 这个方法把路由给注入到路由表里面,之后就可以访问已注入的路由了:

this.$route.addRoutes(data);

注意 因为使用了addRoutes()这个方法之后,路由表已经可以认为是不可控的了,也就是说,已经注入的路由,没办法在通过官方给的api删除掉(当然,目前官方也没有提供相应的api)。那当我们A帐号退出之后,B帐号登录进来,也会执行 addRoutes() 这个方法,会一直累加上去,然后控制台上也会有警告,出现了重复的路由,然后我们访问A帐号有,B帐号没有的路由时,发现是可以进行访问的。这显然不符合我们的需求。

那么,我们该如何解决这个问题呢?

一种是在用户退出的时候,进行项目的重载:

location.href = '/'; //这种相对来说体验就非常差了,相当于重新刷新了页面,显然也是不符合我们的需求

还有一种就是重新初始化静态路由表: 首先,我们要对 router/index 进行改造一下:

const createRouter = () => new Router({
  routes: [{
    path: '/',
    redirect: '/login'
  }, {
    path: '/login',
    name: 'login',
    component: Login
  }]
})

const router = createRouter()

//重新实例化一个新的路由表,替换之前的路由表,然后将这个方法导出
export function resetRouter() {
  const newRouter = createRouter();
  router.matcher = newRouter.matcher; // the relevant part
}

然后,我们在用户退出的时候,重新执行下 resetRouter() 这个方法就可以重新初始化静态路由表,同时也发现B账号进来之后,只能访问对应的路由权限而已。A账号的权限路由已经不存在了。

结语

这是我个人对于路由权限控制的一点理解,如果文中有错误的地方,或者还有其他更好的方案的话,欢迎提出。

### Vue 实现路由权限控制的方法或示例代码 在 Vue 项目中实现路由权限控制,通常需要结合 `vue-router` 和 `Vuex` 来完成动态路由注册和权限验证。以下是具体的实现方法和示例代码: #### 方法一:使用 `router.beforeEach()` 进行权限拦截 通过 `router.beforeEach()` 拦截器对用户访问的路由进行权限校验,确保用户只能访问其有权限的页面。 ```javascript // router/index.js import Vue from 'vue'; import Router from 'vue-router'; import store from '@/store'; // 引入 Vuex store Vue.use(Router); const router = new Router({ routes: [ { path: '/login', name: 'Login', component: () => import('@/views/Login') }, { path: '/404', name: 'NotFound', component: () => import('@/views/NotFound') } ] }); router.beforeEach((to, from, next) => { const requireAuth = to.meta.requireAuth; // 判断是否需要登录权限 const isLogin = store.getters.isLogin; // 获取用户的登录状态 if (requireAuth && !isLogin) { next('/login'); // 如果未登录且目标页面需要权限,则跳转到登录页 } else { const userPermissions = store.getters.userPermissions; // 假设从 Vuex 中获取用户权限列表 if (userPermissions.indexOf(to.name) === -1 && to.name !== 'Login') { next('/404'); // 如果没有权限访问该页面,则跳转到404页面 } else { next(); // 否则允许访问 } } }); export default router; ``` #### 方法二:动态添加路由 通过 `router.addRoutes()` 动态注册用户可访问的路由,确保用户只能看到其权限范围内的菜单。 ```javascript // store.js import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: { dynamicRoutes: [], // 动态路由 userPermissions: [] // 用户权限列表 }, getters: { addRouters: state => state.dynamicRoutes, userPermissions: state => state.userPermissions }, mutations: { SET_DYNAMIC_ROUTES(state, routes) { state.dynamicRoutes = routes; }, SET_USER_PERMISSIONS(state, permissions) { state.userPermissions = permissions; } }, actions: { generateRoutes({ commit }, role) { let accessedRoutes; if (role === 'admin') { accessedRoutes = allRoutes; // 假设 admin 可以访问所有路由 } else { accessedRoutes = filterRoutes(allRoutes, role); // 根据角色过滤路由 } commit('SET_DYNAMIC_ROUTES', accessedRoutes); return accessedRoutes; } } }); ``` ```javascript // main.js import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; Vue.config.productionTip = false; // 初始化路由 store.dispatch('generateRoutes', 'userRole').then(routes => { router.addRoutes(routes); // 动态添加路由 }); new Vue({ router, store, render: h => h(App) }).$mount('#app'); ``` #### 注意事项 - 动态添加路由时,应将诸如 404 页面等通用路由放在最后[^1]。 - 权限校验逻辑可以根据项目的实际需求调整,例如通过后端接口获取用户权限[^2]。 - 使用 `Vuex` 管理用户权限和动态路由,确保数据一致性[^3]。 ```javascript // 示例:过滤路由函数 function filterRoutes(routes, role) { return routes.filter(route => route.meta.roles.includes(role)); } ``` ###
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值