赞
踩
权限管理的应用
vue 项目中的权限管理
权限管理大家一定再熟悉不过,就是不同角色拥有不同的权限(就像我们登陆游戏只能进行自身的基本配置,而管理员就可以进行全服的统一配置)。那么对于 vue 项目如何更好的进行权限的分配,愿本文观点对您有所帮助。
router.addRoutes api 地址:router.addRoutes)当用户登陆成功后,后台返回此用户所拥有的用户信息以及用户权限 ,通过 sessionStorage、localStorage、cookie 等把数据存放在本地。然后通过本地存储把数据存放在 vuex 中进行统一管理(防止刷新页面,vuex 数据丢失),此处用 vuex 对数据进行集中管理,只为后续使用方便。
menus: [ //模拟超级管理员权限数据 { path: '/', //路由地址 lable: '首页', //路由名称 icon: 'discount', //icon 图标 url: 'Home/Home', //路由对应组件路径(生成动态路由时拼接) }, { path: '/video', lable: '视频管理', icon: 'picture-outline', url: 'Video/Video', }, { path: '/user', lable: '用户管理', icon: 'user', url: 'UserMessage/UserMessage', }, { lable: '其他', icon: 'coin', children: [ { path: '/page1', lable: '页面1', icon: 'user', url: 'Other/Page1', }, { path: '/page2', lable: '页面2', icon: 'user', url: 'Other/Page2', }, ], }, ], token1:'Ivj6eZRx40+MTx2ZvnG8nA', //模拟超级管理员登录返回的 token noneMenus:[ //模拟普通用户权限数据 { path: '/', lable: '首页', icon: 'discount', url: 'Home/Home', }, { path: '/video', lable: '视频管理', icon: 'picture-outline', url: 'Video/Video', } ], token2:'Ivj6eZRx40+MTx2ZvnG8nB' //模拟普通用户登录返回的 token
注意:此数据既用于菜单栏的显示,也用于动态的渲染路由;其中的 token 字符串用于模拟登录身份验证,其将保存在本地(下文包含)
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { isCollapse: false, menu: [], token: '', currentMenu: null, todoList: [{ path: '/', lable: '首页', icon: 'discount', }] }, mutations: { // 登陆成功把菜单列表存在sessionStrong中 setMenu(state, val) { state.menu = val; sessionStorage.setItem('menu', JSON.stringify(val)) }, // 清空sessionStrong cleareMenu(state) { state.menu = []; sessionStorage.removeItem('menu'); }, // 根据后台返回数据(动态渲染路由) addRouter(state, router) { if (!sessionStorage.getItem('menu')) { //首先判断 sessionStorage 中是否存在 menu return } let menu = JSON.parse(sessionStorage.getItem('menu')); //从本地存储中获取菜单 state.menu = menu; //避免舒心state 数据丢失 // 在菜单下追加动态路由 let currentMenu = [{ //基本路由(每个用户皆有) path: '/', component: () => import (`../views/Main/Main.vue`), children: [] }] menu.forEach(item => { if (item.children) { item.children = item.children.map(item => { item.component = () => import ('../views/' + item.url) return item }) currentMenu[0].children.push(...item.children) } else { item.component = () => import ('../views/' + item.url) currentMenu[0].children.push(item) } }) router.addRoutes(currentMenu) }, // 保存后台返回的token setToken(state, val) { state.token = val; sessionStorage.setItem('token', val); }, // 清空token clearToken(state) { state.token = ''; sessionStorage.removeItem('token') }, selectMenu(state, val) { // val.path != '/' ? state.currentMenu = val : state.currentMenu = null if (val.path != '/') { state.currentMenu = val; let result = state.todoList.some(item => item.path == val.path) //#判断是否已经添加过 result == true ? '' : state.todoList.push(val) } else { state.currentMenu = null } }, changeCollapse(state) { state.isCollapse = !state.isCollapse }, closeTab(state, val) { //#关闭菜单,删除对应的标签 let index = state.todoList.findIndex(item => item.path == val.path); state.todoList.splice(index, 1) } }, actions: {}, modules: {} })
注意:此处动态追加路由方法为服务器端返回了路由对应的路径。若服务器无返回路径,我们可以定义全部需要显示的路由,然后根据菜单 名称 或 路径 进行匹配追加
methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { //表单验证(数据格式效验) if (valid) { if (this.ruleForm.name == 'cwen' && this.ruleForm.pass == '123456') { //超级管理员账号 this.$store.commit('cleareMenu'); //先清除菜单,防止用户二次登录(后期用路由守卫登录拦截解决) this.$store.commit('setMenu', this.menus); // 通过 vuex 把获取的后台数据存在sessionStorage 中 this.$store.commit('setToken',this.token1); // 通过vuex 把后台返回的token 保存在sessionStorage 中 this.$store.commit('addRouter', this.$router); // 根据后台数据,动态生成路由 this.$router.push('/'); // 生成动态路由成功后跳转,主页面 (渲染根组件时刷新) } else if ( //普通用户账号 this.ruleForm.name == 'none' && this.ruleForm.pass == '123456' ) { this.$store.commit('cleareMenu'); //先清除菜单,防止用户二次登录(后期用路由守卫登录拦截解决) this.$store.commit('setMenu', this.noneMenus); // 通过 vuex 把获取的后台数据存在sessionStorage 中 this.$store.commit('setToken',this.token2); // 通过vuex 把后台返回的token 保存在sessionStorage 中 this.$store.commit('addRouter', this.$router); // 根据后台数据,动态生成路由 this.$router.push('/'); // 生成动态路由成功后跳转,主页面 (渲染根组件时刷新) } else { return this.$message.error('用户名或密码有误'); } } else { return false; } }); }, //---------------------------华丽分割线------------------------------------------------------ //main.js //实例渲染时用钩子获取路由数据(防止路由追加失败) new Vue({ router, store, render: h => h(App), created() { store.commit('addRouter', router) } }).$mount('#app')
补充:此处的用户登录为简洁模拟,但基本业务逻辑皆可实现。关于菜单栏的数据渲染,可参照 NavMenu 导航菜单 进行自行配置
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const routes = [{ path: '/login', component: () => import ( /* webpackChunkNmae:"login"*/ '../views/Login/Login.vue'), } // 此处路由全部由后台返回数据,动态渲染 // { // path: '/', // component: () => // import ( /*webpackChunkName: "home" */ '../views//Main/Main.vue'), // children: [{ // path: '/', // component: () => // import ( /*webpackChunkName: "home" */ '../views/Home/Home.vue') // }, { // path: '/video', // component: () => // import ( /*webpackChunkName: "home" */ '../views/Video/Video.vue') // }, { // path: '/user', // component: () => // import ( /*webpackChunkName: "home" */ '../views/UserMessage/UserMessage.vue') // }, { // path: '/page1', // component: () => // import ( /*webpackChunkName: "home" */ '../views/Other/Page1.vue') // }, { // path: '/page2', // component: () => // import ( /*webpackChunkName: "home" */ '../views/Other/Page2.vue') // }] // } ] const router = new VueRouter({ routes }) router.beforeEach((to, from, next) => { //路由守卫 完成身份验证 // 防止处于首页的用户访问登录页 if (sessionStorage.getItem('token') && to.path == '/login') return next('/'); // 判断用户是否处于登录状态 if (!sessionStorage.getItem('token') && to.path !== '/login') { next('/login') } else { next() } }) //# 重复点击报错问题(降低版本 或者 加以下代码(对 router.push() 方法进行更改);也可使用菜单的 router 属性,进行点击路由跳转) const originalPush = VueRouter.prototype.push VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => err) } export default router
注意:注释部分为之前的静态路由,router.beforeEach() 路由守卫阻止用户无权限跳转
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。