后台管理系统都有这种需求,不同角色账号进来后,就只能看到自己权限内的页面
这种权限限制,需要前后端共同完成。后端需要在用户越权访问时,返回错误提示。
也可让后端直接返回路由列表。只是这样不够灵活,之后每新增一个页面都要他们配置路由和权限,不符合前后端分离原则。
import layoutHeaderAside from '@/layout/header-aside' // 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载 const _import = process.env.NODE_ENV === 'development' ? file => require('@/views/' + file).default : file => () => import('@/views/' + file) /** * 在主框架内显示 */ const frameIn = [ { path: '/', redirect: { name: 'index' }, component: layoutHeaderAside, children: [ // 首页 { path: '/index', name: 'index', component: _import('system/index') }, // 刷新页面 必须保留 { path: '/refresh', name: 'refresh', hidden: true, component: _import('system/function/refresh') }, // 页面重定向 必须保留 { path: '/redirect/:route*', name: 'redirect', hidden: true, component: _import('system/function/redirect') } ] } ] /** * 在主框架之外显示 */ const frameOut = [ // 登录 { path: '/login', name: 'login', component: _import('system/login') } ] /** * 错误页面 */ const errorPage = [ { path: '*', name: '404', component: _import('system/error/404') } ] // 导出需要显示菜单的 export const frameInRoutes = frameIn // 重新组织后导出 export default [ ...frameIn, ...frameOut, ...errorPage ]
import layoutHeaderAside from '@/layout/header-aside' const _import = process.env.NODE_ENV === 'development' ? file => require('@/views/' + file).default : file => () => import('@/views/' + file) const lists = [ { path: '/', redirect: { name: 'index' }, component: layoutHeaderAside, children: [ // 机构管理 { path: '/organization-management', name: 'organizationManagement', meta: { title: '机构管理', auth: true, roles: [0] // 有权进入的角色 }, component: _import('pages/organization-management') }, // 人员管理 { path: '/personnel-management', name: 'personnelManagement', meta: { title: '人员管理', auth: true, roles: [0] }, component: _import('pages/personnel-management') }, // 角色管理 { path: '/roles-management', name: 'rolesManagement', meta: { title: '角色管理', auth: true, roles: [0] }, component: _import('pages/roles-management') }, // 角色授权 { path: '/roles-impower', name: 'rolesImpower', meta: { title: '授权', auth: true, roles: [0] }, component: _import('pages/roles-management/components/roles-impower') }, { path: 'authority-management', name: 'authority-management', meta: { title: '权限管理', auth: true, roles: [0] }, component: _import('pages/authority-management') }, { path: 'agency-register-approval', name: 'agency-register-approval', meta: { title: '机构注册审批', auth: true, roles: [1] }, component: _import('pages/agency-register-approval') }, { path: 'program-info-management', name: 'program-info-management', meta: { title: '项目信息管理', auth: true, roles: [1] }, component: _import('pages/program-info-management') }, { path: 'product-category-management', name: 'product-category-management', meta: { title: '产品类目管理', auth: true, roles: [1] }, component: _import('pages/product-category-management') } ] } ] export default lists
// 菜单 侧边栏 export default [ { path: '/index', title: '首页', icon: 'home', roles: [0, 1] }, { path: '/organization-management', title: '机构管理', icon: 'institution', roles: [0] }, { title: '用户管理', icon: 'user', roles: [0], children: [ { path: '/personnel-management', title: '人员管理', icon: '', roles: [0] }, { path: '/roles-management', title: '角色管理', icon: '', roles: [0] } ] }, { title: '权限管理', icon: 'shield', roles: [0], children: [ { path: '/authority-management', title: '权限管理', icon: '', roles: [0] } ] }, { title: '注册审批', icon: 'legal', roles: [1], children: [{ path: '/agency-register-approval', title: '机构注册审批', icon: '', roles: [1] }] }, { title: '项目管理', icon: 'window-restore', roles: [1], children: [{ path: '/program-info-management', title: '项目信息管理', icon: '', roles: [1] }] }, { title: '类目管理', icon: 'database', roles: [1], children: [{ path: '/product-category-management', title: '产品类目管理', icon: '', roles: [1] }] } ]
import routes from './routes' // 侧边栏菜单数据 import menuAside from '@/menu/aside' /** * 路由拦截 * 权限验证 */ router.beforeEach(async (to, from, next) => { // 进度条 NProgress.start() // 关闭搜索面板 store.commit('d2admin/search/set', false) async function getRouteAndMenu () { await store.dispatch('d2admin/user/GenerateRoutes') // 获取可访问路由,在 vuex 中保存 router.addRoutes(store.state.d2admin.user.accessedRouters) // 和原有的固定路由合并到一起 // 获取侧边栏菜单,在 vuex 中保存 await store.dispatch('d2admin/menu/GenerateMenu', { role: store.state.d2admin.user.info.role, menuAside }) // 设置侧边栏菜单 store.commit('d2admin/menu/asideSet', store.state.d2admin.menu.aside) next({ ...to, replace: true }) // hack 以确保路由增加后,再进行跳转 } if (from.name === null && to.name === '404') { // 避免刷新出现 404 页面 getRouteAndMenu() } // 在需要验证的路由中,进一步判断角色路由 if (to.matched.some(r => r.meta.auth)) { // 将cookie里是否存有token作为验证是否登录的条件 const token = util.cookies.get('token') if (token && token !== 'undefined') { const accessedRouters = store.state.d2admin.user.accessedRouters if (accessedRouters.length <= 0) { // 本地没有保存可访问路由,就需要计算 getRouteAndMenu() } else { next() } } else { // 没有登录的时候跳转到登录界面 // 携带上登陆成功之后需要跳转的页面完整路径 next({ name: 'login', query: { redirect: to.fullPath } }) NProgress.done() } } else { // 不需要身份校验 直接通过 next() } })
actions: { /** * @description 登录 * @param {Object} context * @param {Object} payload username {String} 用户账号 * @param {Object} payload password {String} 密码 * @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式 */ // 登录后保存用户角色信息 login ({ dispatch }, { username = '', password = '' } = {}) { return new Promise((resolve, reject) => { // 开始请求登录接口 AccountLogin({ username, password }) .then(async res => { // 设置 cookie 一定要存 uuid 和 token 两个 cookie // 整个系统依赖这两个数据进行校验和存储 // uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复 // token 代表用户当前登录状态 建议在网络请求中携带 token // 如有必要 token 需要定时更新,默认保存一天 util.cookies.set('uuid', res.userId) util.cookies.set('token', res.token) // 设置 vuex 用户信息,保存用户名称和用户角色 await dispatch('d2admin/user/set', { name: res.userName, role: res.userType }, { root: true }) // 用户登录后从本地储存中加载一系列的设置 await dispatch('load') // 结束 resolve() }) .catch(err => { console.log('err: ', err) reject(err) }) }) } }
// 原始菜单列表 import authRoutes from '@/router/auth-routes' // 判断当前路由字段的 roles 数组里是否包含用户角色 function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return route.meta.roles.some(role => role === roles) } else { return true } } export default { namespaced: true, state: { // 用户信息 // 其中的 role , 0 是管理员, 1 是非管理员 info: {}, accessedRouters: [] }, mutations: { // 保存当前用户的可访问路由 setRouters (state, routers) { state.accessedRouters = routers } }, actions: { // 生成根据权限可访问的路由 // 保存并返回 GenerateRoutes({ state, commit }) { return new Promise(resolve => { const { role } = state.info; const accessedRouters = authRoutes.filter(v => { if (hasPermission(role, v)) { if (v.children && v.children.length > 0) { v.children = v.children.filter(child => { if (hasPermission(role, child)) { return child } return false; }); return v } else { return v } } return false; }); commit('setRouters', accessedRouters); resolve(accessedRouters); }) } } }
与路由 module 一样步骤