Vue动态匹配路由及用户权限过滤
Vue动态匹配路由这个研究了大半天了,由于对vue不是很熟悉,所以走了很多弯路,这里记录一下开发步骤,参考链接https://juejin.im/post/591aa14f570c35006961acac思路用户登录,获取token,把token存入cookie使用router.beforeEach判断用户是否已经拉取用户信息,如果没有,则拉取用户信息根据token获取用户可访问的...
·
Vue动态匹配路由
这个研究了大半天了,由于对vue不是很熟悉,所以走了很多弯路,这里记录一下开发步骤,参考链接
https://juejin.im/post/591aa14f570c35006961acac
思路
- 用户登录,获取token,把token存入cookie
- 使用router.beforeEach
- 判断用户是否已经拉取用户信息,如果没有,则拉取用户信息
- 根据token获取用户可访问的路由表
- 动态添加可访问路由表
具体步骤和代码展示
user.js
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import qs from 'qs'
const user = {
state: {
token: getToken(),
name: '',
roles: [],
asyncRouterMap: []
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
SET_ROUTER: (state, asyncRouterMap) => {
state.asyncRouterMap = asyncRouterMap
}
},
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
const params = qs.stringify({ username: username, password: userInfo.password })
login(params).then(response => {
const data = response.data.data
setToken(data.token)
commit('SET_TOKEN', data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const data = response.data.data
// 验证返回的roles是否是一个非空数组
if (data.roles && data.roles.length > 0) {
commit('SET_ROLES', data.roles)
}
commit('SET_NAME', data.name)
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// 登出
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
// console.log(state.token)
logout().then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
localStorage.setItem('User-Roles', '')
removeToken()
resolve()
}).catch(error => {
reject(error)
})
})
},
}
}
export default user
permission.js
import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { Message } from 'element-ui'
import { getToken } from '@/utils/auth' // 验权
NProgress.configure({ showSpinner: false })
// 权限判断方法
function hasPermission(roles, permissionRoles) {
if (roles.indexOf('admin') >= 0) return true
if (!permissionRoles) return true
return roles.some(role => permissionRoles.indexOf(role) > -1)
}
// 不重定向白名单
const whiteList = ['/login']
router.beforeEach((to, from, next) => {
NProgress.start()
const token = getToken()
if (token) {
if (to.path === '/login') {
next({ path: '/' })
// if current page is dashboard will not trigger afterEach hook, so manually handle it
NProgress.done()
} else {
// 判断当前用户是否已拉取完user_info信息
if (store.getters.roles.length === 0) {
// 拉取用户信息
store.dispatch('GetInfo').then(res => {
// 根据用户权限生成可访问路由表
store.dispatch('getAsynvRoutes', token).then(res => {
// 动态添加可访问路由表
router.addRoutes(store.getters.addRouters)
// 防止导航留下历史记录
next({ ...to, replace: true })
})
}).catch((err) => {
store.dispatch('FedLogOut').then(() => {
Message.error(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
// 动态改变权限判断路由是否可跳转
if (hasPermission(store.getters.roles, to.meta.permission)) {
next()
} else {
next({ path: '/404', replace: true })
}
}
}
} else {
// 未存在登录态(token) 判断是否在免登录白名单中
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
// 否则全部重定向到登录页
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
// 结束Progress
NProgress.done()
})
routerPermission.js
import { constantRouterMap } from '@/router'
import sysPermissionApi from '@/api/merchant/sysPermission.api'
import Layout from '../../views/layout/Layout'
import Vue from 'vue'
function filterRoutes(routers) {
// 转component字段的字符串为import
const routerTree = []
for (let i = 0; i < routers.length; i++) {
const obj = routers[i]
const newObj = {
path: obj.path,
redirect: obj.redirect,
name: obj.name,
meta: { title: obj.title, btnPermission: obj.btns }
}
if (obj.component !== '') {
Vue.set(newObj, 'component', () => import(`@/views/${obj.component}`))
} else {
Vue.set(newObj, 'component', Layout)
}
// 需要递归
if (obj.children.length > 0) {
Vue.set(newObj, 'children', filterRoutes(obj.children))
}
routerTree.push(newObj)
}
return routerTree
}
const permission = {
state: {
routers: constantRouterMap,
addRouters: [],
newAddrouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
// 本地
// state.routers = constantRouterMap
// 动态
// state.routers = routers
// 动态合并本地
state.routers = constantRouterMap.concat(routers)
},
SET_ADDROUTES: (state, routers) => {
state.addRouters = routers
}
},
actions: {
getAsynvRoutes({ commit }, token) {
return new Promise(resolve => {
sysPermissionApi.getRolePermissionTree(token).then(res => {
const accessedRouters = filterRoutes(res.data.data)
commit('SET_ADDROUTES', accessedRouters)
commit('SET_ROUTERS', accessedRouters)
resolve(accessedRouters)
})
})
}
}
}
export default permission
btnPermission.js
export default (Vue) => {
Vue.directive('btnPermission', {
bind: function(el, binding, vnode) {
const value = binding.value
if (!vnode.context.$route.meta || !vnode.context.$route.meta.btnPermission) return false
const permissionList = vnode.context.$route.meta.btnPermission
if (value && typeof value === 'string') {
const hasPermission = value in permissionList
// 还需要做角色判断
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error('binding value must be a string!')
}
}
})
}
后端返回的数据格式
{
"code": 200,
"data": [{
"children": [{
"children": [],
"component": "merchant/sysRole/index",
"hidden": 1,
"icon": "",
"meta": "",
"name": "SysRole",
"path": "sysRole",
"redirect": "",
"title": "角色"
}],
"component": "",
"hidden": 1,
"icon": "",
"meta": "",
"name": "Merchant",
"path": "/merchant",
"redirect": "/merchant",
"title": "基础设置"
}],
"message": "SUCCESS"
}
页面展示
权限管理页面
用户角色页面
角色分配页面
更多推荐
已为社区贡献3条内容
所有评论(0)