浅谈vue权限管理实现及流程

后端返回用户权限,前端根据用户权限处理得到左侧菜单;所有路由在前端定义好,根据后端返回的用户权限筛选出需要挂载的路由,然后使用 addRoutes 动态挂载路由。

二、实现要点

(1)路由定义,分为初始路由和动态路由,一般来说初始路由只有 login,其他路由都挂载在 home 路由之下需要动态挂载。
(2)用户登录,登录成功之后得到 token,保存在 sessionStorage,跳转到 home,此时会进入路由拦截根据 token 获取用户权限列表。
(3)全局路由拦截,根据当前用户有没有 token 和 权限列表进行相应的判断和跳转,当没有 token 时跳到 login,当有 token 而没有权限列表时去发请求获取权限等等逻辑。
(4)处理用户权限,在 store.js 定义一个模块 permission.js,专门用于处理用户权限相关的逻辑,用户权限列表、菜单列表都保存在此模块;
(5)用户权限列表、菜单列表的处理,前端的路由要和后端返回的权限有一个唯一标识(一般用路由名做标识符),根据此标识筛选出对应的路由。
(6)左侧菜单,要和用户信息、用户管理模块使用的菜单信息一致,统一使用保存在 store 中的变量。

三、具体实现流程

1、准备工作,路由定义

/* router/indes.js */ /* 初始路由 */ let router = new Router({ mode: 'history', routes: [ { path: '/login', name: 'login', component: () => import('@/views/login.vue'), }, ] });

/* router/indes.js */ /* 准备动态添加的路由 */ export const dynamicRoutes = [ { path: 'https://www.jb51.net/', name: 'home', component: () => import('@/views/home.vue'), meta: { requiresAuth: true, }, children: [ // 用户信息 { path: '/user-info', name: 'user-info', component: () => import('@/views/user-setting/user-info.vue'), }, // 修改密码 { path: '/user-password', name: 'user-password', component: () => import('@/views/user-setting/user-password.vue'), }, ] }, { path: '/403', component: () => import('@/views/error-page/403'), }, { path: '*', component: () => import('@/views/error-page/404'), }, ];

系统主要页面的路由,后续会将这些路由经过权限筛选,添加到 home 路由的 children 里面

/* router/router.js */ export default [ // 部署管理 { path: '/deploy-manage', name: 'deploy-manage', component: () => import('@/views/sys-admin/deploy-manage/deploy-manage.vue'), meta: { permitName: 'deploy-manage', } }, // ... ];

2、用户登录

用户进入登录页,输入用户名、密码、验证码,点击登录,发送登录请求,登录成功之后,将 token 保存在 sessionStorage,然后跳转到首页 /home ,进入路由拦截的逻辑。

/* login.vue */ // 发送登录请求 vm.$http.login(params, data => { sessionStorage.token = data.token; // ... // 跳转到首页 home。这里会触发全局路由拦截 router.beforeEach vm.$router.push({ name: 'home' }); }, err => { console.log(err); });

3、全局路由拦截

首先从打开本地服务 :2001 开始,打开后会进入 login 页面,那么判断的依据是什么?

首先是 token。没有登录的用户是拿不到 token 的,而登录后的用户我们会将 token 存到 seesionStorage,因此,根据当前有没有 token 即可知道是否登录。

/* 全局路由拦截 */ router.beforeEach((to, from, next) => { // 根据有没有token判断是否登录 if (!sessionStorage.token) { // 1、当用户打开localhost,to.matched === [],匹配的是空路由,此时需要重定向到login // 2、重定向到login之后,to.matched === [name: "login", path: "/login"...] 就是上一步的login页面 // to.matched.some(item => item.meta.requiresAuth) 这句的意思是 进入的路由页需要登录认证,取反就是不用登录,直接通过 if (to.matched.length > 0 && !to.matched.some(item => item.meta.requiresAuth)) { next(); // 跳过,进入下一个导航钩子。比如:在 /login 路由页刷新页面会走到此逻辑 } else { next({ path: '/login' }); } } else { // 现在有token了 if (!store.state.permission.permissionList) { // 如果没有 permissionList,发请求获取用户权限列表 store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path, query: to.query }); }); } else { // 现在有 permissionList 了 if (to.path !== '/login') { if (to.matched.length === 0) { // 如果匹配到的路由形如 https://172.24.1.117/?id=xxx&name=xxx,表明是关联跳转时没有权限,跳转到403 next({ path: '/403' }); } else if (queryChange) { // 跳转之前将路由中查询字符串为空的过滤掉,如 xxx.com?page=&size= 这种 next({ name: to.name, params: to.params, query: to.query }); } else if (sessionStorage.isSysLock === 'true' && to.path !== '/sys-lock') { next({ path: '/sys-lock' }); } else { next(); } } else { // 1.如果用户手动在地址栏输入 /login,重定向到之前的路由页 // next(from.fullPath); // 2.如果用户手动在地址栏输入 /login,清除token并刷新页面,就会去到登录页 store.commit('goToLogin'); } } } });

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/80a768891f2b0b2de0e0681a7b2f2a10.html