有模板做ppt的网站有哪些,企业信用信息网,网页代码小游戏,爱论网一、权限控制管理#xff1a;
对于企业级的项目, 我们可能需要对项目做权限控制管理, 实现不同角色的用户登录项目根据所拥有的权限访问不同的页面内容#xff0c;此时就需要使用到动态路由来对权限页面做限制。
【使用vue-router实现动态路由#xff0c;达到实现菜单权限… 一、权限控制管理
对于企业级的项目, 我们可能需要对项目做权限控制管理, 实现不同角色的用户登录项目根据所拥有的权限访问不同的页面内容此时就需要使用到动态路由来对权限页面做限制。
【使用vue-router实现动态路由达到实现菜单权限控制的功能】
二、实现思路
1.动态路由 将拥有权限的路由单独从路由表系统中提出视为动态路由待后续根据用户权限来导入拥有权限的动态路由
2.权限与动态路由绑定 用户登录之后需要获取该用户所拥有的权限该权限前后端需要协调一致需要对应前端拥有权限的动态路由后端可以返回动态路由的name来做以区分也可以在前端单独定义每个动态路由(权限)的标识进行权限的区分(我使用的方法因为后台的权限分配有自己的逻辑不需要再次改动只需在前端的动态路由中定义该路由的权限标识即可)
3.获取权限筛选动态路由 获取到用户所拥有的权限之后将后端返回的权限标识与动态路由中所定义的权限标识比对筛选出该用户所拥有的权限(动态路由)
4.添加权限(动态路由) 使用router.addRoute()方法将拥有权限的动态路由添加到路由表系统中实现权限的控制(vue-router4.x版本已废弃router.addRoutes()来对动态路由批量导入)
5.渲染菜单 获取到拥有权限的动态路由之后在vuex/pinia中去组合需要渲染菜单的动态路由(/静态路由)菜单需要在路由中按需定义菜单的名称、图片、icon等等最后将路由中组合好的菜单循环渲染展示(不能使用router.options来获取所有的路由渲染菜单因为该方法不能获取到动态路由)
6.退出登录删除动态路由(权限) 用户退出登录时需要删除动态路由(权限)因为如果退出登录时不删除动态路由(权限)紧接着登录其他权限不同的用户该用户没有上一个用户所拥有的权限所以无法查看上一个用户所看到的菜单以及页面但是该用户可以使用浏览器的回退功能或者修改url地址栏的路径去访问上一个用户能访问的页面这样该用户就可以访问到不属于自己权限的页面所以在用户退出登录时需要删除动态路由(权限)来保证权限的准确性。删除动态路由使用到router.removeRoute()
三、实现代码
第一步 提取动态路由每个动态路由中的meta对象中定义了要渲染菜单的名称的title和图片imgpermissionCode定义的标识为与后端确定的该用户是否具有该路由菜单的权限。
/*** router/system/index.js* 权限的动态路由*/
export const changeChildRouter [{path: user,name: SysUser,component: () import(/* webpackChunkName:system */../../views/System/UserManage),meta: {title: 用户管理,permissionCode: 10004,img: require(/assets/images/Tree/setting-user.png)}},{path: department,name: SysDepartment,component: () import(/* webpackChunkName:system */../../views/System/DepartmentManage),meta: {title: 部门管理,permissionCode: 10404,img: require(/assets/images/Tree/setting-gis.png)}},{path: position,name: SysPosition,component: () import(/* webpackChunkName:system */../../views/System/PositionManage),meta: {title: 岗位管理,permissionCode: 10204,img: require(/assets/images/Tree/setting-user.png)}},{path: role,name: SysRole,component: () import(/* webpackChunkName:system */../../views/System/RoleManage),meta: {title: 角色管理,permissionCode: 10104,img: require(/assets/images/Tree/setting-user.png)}},
]
第二步 登录之后获取该登录用户的权限筛选动态路由。开始有两种想法
第一种想法 当用户登录之后紧接着在逻辑当中获取该用户的权限将用户的权限存储到session当中目的是为了防止用户刷新浏览器权限依然不会丢失。但是安全性不高用户手动修改session中存储的权限就会导致权限丢失或者非法获取其他用户的session权限放置未拥有该权限的用户的session中导致该用户拥有了其他用户不属于自己的权限等等问题所以我应用了第二种想法第二种想法 当用户登录之后在路由前置守卫router.beforeEach()中去获取权限获取到权限之后引入并筛选出该用户权限的动态路由使用router.addRoute()将该用户的动态路由添加到路由表系统当中。将筛选出到的动态路由(权限)存储到vuex当中。由于vuex做临时存储所以原理上刷新页面之后vuex中的数据就会丢失但是在router.beforeEach()路由前置守卫中获取权限就解决了该问题每次刷新页面都会先执行router.beforeEach() 所以每次刷新页面都会先去获取该用户的权限将根据后端返回的权限标识筛选出的动态路由存储到vuex当中。但是想要实现刷新页面动态路由权限页面不丢失不能将404页面定义为静态路由放置在路由表系统当中需要随权限获取后动态添加404页面目的是为了解决刷新权限页面之后权限丢失在没有重新获取到权限的时候检测到路由表系统当中不存在该动态路由所以直接进入404页面的问题。【代码示例如下】
/*** permission.js* 权限控制管理*/
import router from /router
import store from /store
import { changeChildRouter } from /router/system// 防止路由无限循环
let routeFlag false;
// 导航守卫
router.beforeEach(async (to, from, next) {let token localStorage.getItem(token);// 如果没有token并且当前不是登录页就跳转到登录界面if (!token !to.path.includes(/login)) {routeFlag falsenext(/login)} else if (to.path.includes(/login)) {routeFlag falsenext()} else {if (routeFlag) return next()// 权限控制routeFlag true// 1. 根据上面定义的 routeFlag 得出: 用户没有获取权限/刷新页面权限丢失则先调用获取权限的接口const res await store.dispatch(menu/MenuInfo)// 2. 从后端返回的权限中筛选出权限的标识 roleId, 对应前端动态路由中绑定的权限的标识 permissionCodeconst Liststr res.map(item item.roleId)// 3. 系统管理--权限: changeChildRouter 所有的动态路由const systemRoutes systemAsyncRouter(changeChildRouter, Liststr)// 4. 保存动态路由(权限)为了退出登录之后删除asyncRoutes(systemRoutes)// 5. 添加 404 路由router.addRoute({path: /:pathMatch(.*)*,name: 404,component: () import(/* common *//views/NotFound),meta: { title: 404 }},)next({...to,// 重新进入replace: true // 不保存本次进入页面的路由历史记录})}
})// 系统管理——权限
function systemAsyncRouter(routes, codes) {// 1. 根据接口返回的权限找到可以访问的路由const filterRoutes routes.filter(item codes.includes(item.meta?.permissionCode))// 2. 添加动态路由addAsyncRouter(系统功能, filterRoutes)// 3. 将动态路由添加到vuex中和静态路由合并渲染侧边栏菜单store.commit(menu/setMenuList, filterRoutes)return filterRoutes
}// 将动态路由添加到路由表系统中
function addAsyncRouter(parentName, asyncRoutesList) {asyncRoutesList.map(item {// 可能会存在没有定义的组件的父级路由, 目的是渲染菜单时, 该路由只做子级路由的归类(仅用于展示) if (!item.component) return addAsyncRouter(parentName, item.children)router.addRoute(parentName, item) // 添加动态路由})
}// 保存所有的动态路由, 使用展开运算符优化写法后续有其他的动态路由直接依次传入实参即可
function asyncRoutes(...args) {store.commit(menu/setPermissionRouteList, [].concat(...args))
}
上述代码使用到了router.addRoute()将路由添加至路由表当中但是在此传递了两个参数
第一个参数 为需要添加的动态路由的一级路由的name第二个参数 动态路由本身
如果只传递了一个动态路由本身的参数则表示该动态路由为一级路由
第三步 添加动态路由之后需要在用户退出的时候调用以下方法删除动态路由以及保存的权限
/*** permission.js* 权限控制管理*/// 退出登录时删除动态路由以及vuex中保存的动态路由防止下一个用户登录时回退查看到上一个用户的动态路由(权限)
export function removeAsyncRouter() {// 所有的动态路由const permissionRouteList store.state.menu.permissionRouteListconst removeRouteFn (permissionRouteList) {if (permissionRouteList.length 0) {permissionRouteList.map(item {if (!item.component item.children) return removeRouteFn(item.children)// 删除动态路由,保证用户退出后下一个用户登录时不会回退到上一个用户的路由router.removeRoute(item.name)})}}removeRouteFn(permissionRouteList)// 清空动态路由的左侧菜单store.commit(menu/setMenuList, [])// 清空动态路由的权限标识store.commit(menu/setPermissionCodeList, [])
} 上述代码中使用router.removeRoute()来删除动态路由, 该方法接收一个参数: 路由的name, 即可将该name的路由从路由表当中删除。
第四步 在vuex当中将动态路由(/静态路由)组合来渲染权限菜单展示
/*** store/menu.js* 权限菜单*/import { loadAuthority } from /api/loaddata
import { systemChildRouter } from /router/system
const state () ({permissionCodeList: [], // 该用户有权限对应的动态路由的标识permissionRouteList: [], // 动态路由单独保存一份为了退出登录的时候删除动态路由menuList: [], // 系统管理: 静态路由动态路由渲染左侧菜单
})const mutations {// 添加权限路由对应的权限标识setPermissionCodeList(state, permissionCodeList) {state.permissionCodeList permissionCodeList},// 动态路由集合setPermissionRouteList(state, permissionRouteList) {state.permissionRouteList permissionRouteList},// ********** 系统管理路由权限 ***********setMenuList(state, permissionRouteList) {const menuList [...systemChildRouter, ...permissionRouteList]},
}const actions {// 获取该用户的权限项async MenuInfo(ctx) {const res await loadAuthority.getUserAuthList({ userName: localStorage.getItem(userName) })ctx.commit(setPermissionCodeList, res)return res}
}export default {namespaced: true,state,actions,mutations
}
在vuex store中组合了渲染菜单的: 动态路由静态路由, 由于提前已经将渲染菜单的名称和图片定义在了每个路由当中,所有组合要渲染菜单的路由之后, 即可在vue组件中去循环渲染权限菜单
第五步 渲染菜单, 在vue组件计算属性当中获取vuex中组合好的渲染菜单的路由, 在模板中循环渲染展示菜单
/*** LeftMenu.vue* 系统管理: 权限侧边栏菜单*/templatea-layout-sider :width220a-menu modeinline v-model:selectedKeyscurrent!-- 权限菜单 --left-menu-item v-foritem in menuList :keyitem.path :itemitem/left-menu-item/a-menu/a-layout-sider
/templatescript
import LeftMenuItem from ./LeftMenuItem.vue
export default {name: SystemMenu,components: {LeftMenuItem},data() {return current: [help],};},computed: {menuList() {// 获取渲染菜单的路由数组return this.$store.state.menu.menuList}},
};
/script
在渲染权限侧边栏菜单的LeftMenu.vue组件中, 引入了一个封装的LeftMenuItem.vue组件, 在该组件中实现了具体的渲染菜单的模板代码, 并且使用LeftMenuItem.vue可以使用递归自身来实现可展开菜单的功能。
/*** LeftMenuItem.vue* 封装渲染菜单组件*/
templatediv!-- 如果没有children, 则渲染在侧边栏的一级菜单 --template v-if!item.childrena-menu-item :keyitem.pathtemplate #iconimg :srcitem.meta.img/templaterouter-link :toitem.path{{ item.meta.title }}/router-link/a-menu-item/template!-- 如果有children表明是二级菜单该一级菜单不提供路由只是对二级菜单的归类 --template v-elsea-sub-menu :keyitem.pathtemplate #iconimg :srcitem.meta.img/templatetemplate #title{{ item.meta.title }}/template!-- 递归组件如果子路由里面还有路由则继续渲染它的子路由对应的菜单 --left-menu-item v-foritem in item.children :keyitem.path :itemitem/left-menu-item/a-sub-menu/template/div
/templatescript
export default {name: LeftMenuItem,props: {item: {type: Object,required: true},}
}
/script
style langscss scoped
/style 递归自身组件: 想要递归自身组件, 需要在组件脚本中导出定义自身的name: LeftMenuItem , 在组件内容即可调用自身的name来实现递归调用组件本身。 这样就实现了菜单的权限控制, 拥有不同权限的用户登录之后, 就只会看到属于自己权限的页面~