From 0c6e45e9a1fde6a9c8f147a66dd01c1979f5586d Mon Sep 17 00:00:00 2001 From: Pan Date: Thu, 21 Mar 2019 10:58:44 +0800 Subject: [PATCH] refactor permission --- src/layout/components/Navbar.vue | 3 +- src/permission.js | 82 ++++++++++++++++---------------- src/router/index.js | 22 ++++++--- src/store/modules/permission.js | 3 +- src/store/modules/user.js | 29 ++++++----- src/views/login/index.vue | 15 +++--- 6 files changed, 83 insertions(+), 71 deletions(-) diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 5a2767a5..e2829001 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -79,8 +79,7 @@ export default { }, async logout() { await this.$store.dispatch('user/logout') - // In order to re-instantiate the vue-router object to avoid bugs - location.reload() + this.$router.push(`/login?redirect=${this.$route.fullPath}`) } } } diff --git a/src/permission.js b/src/permission.js index a03f7bda..7cc2a5cf 100644 --- a/src/permission.js +++ b/src/permission.js @@ -7,66 +7,64 @@ import { getToken } from '@/utils/auth' // get token from cookie NProgress.configure({ showSpinner: false }) // NProgress Configuration -// permission judge function -function hasPermission(roles, permissionRoles) { - if (roles.includes('admin')) return true // admin permission passed directly - if (!permissionRoles) return true - return roles.some(role => permissionRoles.indexOf(role) >= 0) -} - const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist -router.beforeEach((to, from, next) => { - NProgress.start() // start progress bar - if (getToken()) { - // determine if there has token +router.beforeEach(async(to, from, next) => { + // start progress bar + NProgress.start() - /* has token*/ + // determine whether the user has logged in + const hasToken = getToken() + + if (hasToken) { if (to.path === '/login') { + // if is logged in, redirect to the home page next({ path: '/' }) - NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it + NProgress.done() } else { - if (store.getters.roles.length === 0) { - // 判断当前用户是否已拉取完user_info信息 - store - .dispatch('user/getInfo') - .then(res => { - // 拉取user_info - const { roles } = res // note: roles must be a object array! such as: [{id: '1', name: 'editor'}, {id: '2', name: 'developer'}] - store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => { - // 根据roles权限生成可访问的路由表 - router.addRoutes(accessRoutes) // 动态添加可访问路由表 - next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record - }) - }) - .catch(err => { - store.dispatch('user/resetToken').then(() => { - Message.error(err) - next({ path: '/' }) - }) - }) + // determine whether the user has obtained his permission roles through getInfo + const hasRoles = store.getters.roles && store.getters.roles.length > 0 + if (hasRoles) { + next() } else { - // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓ - if (hasPermission(store.getters.roles, to.meta.roles)) { - next() - } else { - next({ path: '/401', replace: true, query: { noGoBack: true }}) + try { + // get user info + // note: roles must be a object array! such as: ['admin'] or ,['developer','editor'] + const { roles } = await store.dispatch('user/getInfo') + + // generate accessible routes map based on roles + const accessRoutes = await store.dispatch('permission/generateRoutes', roles) + + // dynamically add accessible routes + router.addRoutes(accessRoutes) + + // hack method to ensure that addRoutes is complete + // set the replace: true, so the navigation will not leave a history record + next({ ...to, replace: true }) + } catch (error) { + // remove token and go to login page to re-login + await store.dispatch('user/resetToken') + Message.error(error || 'Has Error') + next(`/login?redirect=${to.path}`) + NProgress.done() } - // 可删 ↑ } } } else { /* has no token*/ + if (whiteList.indexOf(to.path) !== -1) { - // 在免登录白名单,直接进入 + // in the free login whitelist, go directly next() } else { - next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页 - NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it + // other pages that do not have permission to access are redirected to the login page. + next(`/login?redirect=${to.path}`) + NProgress.done() } } }) router.afterEach(() => { - NProgress.done() // finish progress bar + // finish progress bar + NProgress.done() }) diff --git a/src/router/index.js b/src/router/index.js index fcff584e..6f70e754 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -105,12 +105,6 @@ export const constantRoutes = [ } ] -export default new Router({ - // mode: 'history', // require service support - scrollBehavior: () => ({ y: 0 }), - routes: constantRoutes -}) - export const asyncRoutes = [ { path: '/permission', @@ -383,3 +377,19 @@ export const asyncRoutes = [ { path: '*', redirect: '/404', hidden: true } ] + +const createRouter = () => new Router({ + // mode: 'history', // require service support + scrollBehavior: () => ({ y: 0 }), + routes: constantRoutes +}) + +const router = createRouter() + +// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465 +export function resetRouter() { + const newRouter = createRouter() + router.matcher = newRouter.matcher // reset router +} + +export default router diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js index c697ac61..820ca46b 100644 --- a/src/store/modules/permission.js +++ b/src/store/modules/permission.js @@ -47,9 +47,8 @@ const mutations = { } const actions = { - generateRoutes({ commit }, data) { + generateRoutes({ commit }, roles) { return new Promise(resolve => { - const { roles } = data let accessedRoutes if (roles.includes('admin')) { accessedRoutes = asyncRoutes diff --git a/src/store/modules/user.js b/src/store/modules/user.js index c79f6a62..f27615b0 100644 --- a/src/store/modules/user.js +++ b/src/store/modules/user.js @@ -1,5 +1,6 @@ import { login, logout, getInfo } from '@/api/user' import { getToken, setToken, removeToken } from '@/utils/auth' +import router, { resetRouter } from '@/router' const state = { token: getToken(), @@ -78,6 +79,7 @@ const actions = { commit('SET_TOKEN', '') commit('SET_ROLES', []) removeToken() + resetRouter() resolve() }).catch(error => { reject(error) @@ -95,22 +97,25 @@ const actions = { }) }, - // 动态修改权限 + // Dynamically modify permissions changeRoles({ commit, dispatch }, role) { - return new Promise(resolve => { + return new Promise(async resolve => { const token = role + '-token' + commit('SET_TOKEN', token) setToken(token) - getInfo(token).then(response => { - const { data } = response - const { roles, name, avatar, introduction } = data - commit('SET_ROLES', roles) - commit('SET_NAME', name) - commit('SET_AVATAR', avatar) - commit('SET_INTRODUCTION', introduction) - dispatch('permission/generateRoutes', data) // 动态修改权限后 重绘侧边菜单 - resolve() - }) + + const { roles } = await dispatch('getInfo') + + resetRouter() + + // generate accessible routes map based on roles + const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true }) + + // dynamically add accessible routes + router.addRoutes(accessRoutes) + + resolve() }) } } diff --git a/src/views/login/index.vue b/src/views/login/index.vue index b74512d0..44c6de90 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -135,13 +135,14 @@ export default { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true - // dispatch @/store/modules/user login action - this.$store.dispatch('user/login', this.loginForm).then(() => { - this.loading = false - this.$router.push({ path: this.redirect || '/' }) - }).catch(() => { - this.loading = false - }) + this.$store.dispatch('user/login', this.loginForm) + .then(() => { + this.$router.push({ path: this.redirect || '/' }) + this.loading = false + }) + .catch(() => { + this.loading = false + }) } else { console.log('error submit!!') return false