重要功能总结
权限功能的实现
权限路由思路:
根据用户登录的roles信息与路由中配置的roles信息进行比较过滤,生成可以访问的路由表,并通过router.addRoutes(store.getters.addRouters)动态添加可访问权限路由表,从而实现左侧和顶栏菜单的展示。
实现步骤:
1.在router/index.js中,给相应的菜单设置默认的roles信息;
如下:给"权限设置"菜单设置的权限为:meta:{roles: ['admin', 'editor']},及不同的角色都可以看到; 给其子菜单"页面权限",设置权限为:meta:{roles: ['admin']},及表示只有"admin"可以看到该菜单; 给其子菜单"按钮权限"设置权限为:meta:{roles: ['editor']},及表示只有"editor"可以看到该菜单。
2.通过router.beforeEach()和router.afterEach()进行路由过滤和权限拦截;
代码如下:
// permission judge function function hasPermission(roles, permissionRoles) { if (roles.indexOf('admin') >= 0) return true // admin permission passed directly if (!permissionRoles) return true return roles.some(role => permissionRoles.indexOf(role) >= 0) } const whiteList = ['/login'] // 不重定向白名单 router.beforeEach((to, from, next) => { NProgress.start() // 设置浏览器头部标题 const browserHeaderTitle = to.meta.title store.commit('SET_BROWSERHEADERTITLE', { browserHeaderTitle: browserHeaderTitle }) // 点击登录时,拿到了token并存入了vuex; if (getToken()) { /* has token*/ if (store.getters.isLock && to.path !== '/lock') { next({ path: '/lock' }) NProgress.done() } else if (to.path === '/login') { next({ path: 'https://www.jb51.net/' }) // 会匹配到path:'',后面的path:'*'还没有生成; NProgress.done() } else { if (store.getters.roles.length === 0) { store.dispatch('GetInfo').then(res => { // 拉取用户信息 const roles = res.roles store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表 router.addRoutes(store.getters.addRouters) // 动态添加可访问权限路由表 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 }) }).catch((err) => { store.dispatch('FedLogOut').then(() => { Message.error(err || 'Verification failed, please login again') next({ path: 'https://www.jb51.net/' }) }) }) } else { // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓ if (hasPermission(store.getters.roles, to.meta.roles)) { next()// } else { next({ path: '/401', replace: true, query: { noGoBack: true }}) } } } } else { if (whiteList.indexOf(to.path) !== -1) { next() } else { // 点击退出时,会定位到这里 next('/login') NProgress.done() } } }) router.afterEach(() => { NProgress.done() // 结束Progress setTimeout(() => { const browserHeaderTitle = store.getters.browserHeaderTitle setTitle(browserHeaderTitle) }, 0) })
用户点击登录之后的业务逻辑分析:
1、用户调取登录接口,获取到token,进行路由跳转到首页;
2、通过路由导航钩子router.beforeEach((to,from,next)=>{})函数确定下一步的跳转逻辑,如下:
2.1、用户已经登录成功并返回token值;
2.1.1、lock 锁屏场景;
2.1.2、用户重新定位到登录页面;
2.1.3、根据用户是否有roles信息,进行不同的业务逻辑,如下:
(1)、初始情况下,用户roles信息为空;
通过store.dispatch('GetInfo')调取接口,获取用户信息;
获取到roles信息后,将roles,name,avatar保存到vuex;
同时,通过store.dispatch('GenerateRoutes', { roles })去重新过滤和生成路由,并将重新生成之后的权限路由'routes'保存到vuex;
最后,通过router.addRoutes()合并路由表;
如果在获取用户信息接口时,出现错误,则调取store.dispatch('FedLogOut')接口,返回到login页面;
用户FedLogOut之后,需要情况vuex和localStorage中的token信息;
(2)、用户已经拥有roles信息;
点击页面路由,通过roles权限判断 hasPermission();
如果用户有该路由权限,直接跳转对应的页面;如果没有权限,则跳转至401提示页面;
2.2、用户没有获取到token值;
2.2.1、如果设置了白名单用户,则直接跳转到相应的页面;反之,则跳转至登录页面;
3、通过路由导航钩子函数router.afterEach(() => {}),做收尾工作,如下:
3.1、NProgress.done() // 结束Progress
3.2、获取到title并设置title;
详细代码,请参考src/permission.js
4、权限演示说明
测试账号:
(1). username: admin,password: 123456;admin拥有最高权限,可以查看所有的页面和按钮;
(2). username: editor,password: 123456;editor只有被赋予权限的页面和按钮才可以看到;
三级导航菜单顶部栏展示