后台管理系统-权限管理


后台管理系统-权限管理

操作权限可以通过后台实现,比如增删查改时调接口,根据接口返回的code码,判断是否有操作权限,然后给用户无权限的提示。

但是此做法对用户来说体验并不好,如果没有权限就不展示对应的操作按钮就行了,要做到这点的话,就需要前后端共同完成了。

需要的接口:

1、接口 :供前端添加菜单导航、按钮等

2、接口: 供前端给对应的操作添加权限

3、接口: 供前端获取有权限的操作按钮

前端操作:

1、获取当前路由及子路由下有权限的按钮,并将其存入sessionStorage

2、根据接口返回的数据,动态的展示有权限的按钮

前端主要代码如下:

  1 const state = {
  2   menuTree: [], // 菜单列表
  3   btnPermission: JSON.parse(sessionStorage.getItem('btnPermission')) || [], // 按钮权限
  4 }
  5 
  6 const mutations = {
  7   SET_BTN_PERMISSIONS(state, data) {
  8     state.btnPermission = data
  9     sessionStorage.setItem('btnPermission', JSON.stringify(data))
 10   },
 11 }
 12 
 13 // 判断当前路由是否在资源菜单内
 14 const isInMenu = (arr, string) => {
 15   let bool = false
 16   ;(function getBool(arr, string) {
 17     for (const x of arr) {
 18       if (x.menuRouterPath === string) {
 19         bool = true
 20         return
 21       }
 22       getBool(x.children, string)
 23     }
 24   })(arr, string)
 25 
 26   return bool
 27 }
 28 
 29 // 找到对应资源菜单下的子菜单(按钮)map
 30 const filterBtnRoutes = (arr, string) => {
 31   let res = []
 32   ;(function gerRoute(arr, string) {
 33     for (const x of arr) {
 34       if (x.menuRouterPath === string) {
 35         res = x.children
 36         return res
 37       }
 38       gerRoute(x.children, string)
 39     }
 40   })(arr, string)
 41   return res
 42 }
 43 
 44 // 按钮下级可能还有按钮,循环获取当前路由下的所有按钮
 45 const flatten = arr => {
 46   const flattend = []
 47   ;(function flat(arr) {
 48     arr.forEach(x => {
 49       flattend.push(x)
 50       if (Array.isArray(x.children) && x.children.length > 0) {
 51         flat(x.children)
 52       }
 53     })
 54   })(arr)
 55   return flattend
 56 }
 57 
 58 const actions = {
 59   getBtnPermissions({ state, commit }, params) {
 60     // 判断当前路由是否在资源菜单内
 61     const isMenu = isInMenu(state.menuTree, params)
 62 
 63     // 当其在资源菜单内,路由变更更新按钮权限,否则为子页面,保留按钮权限
 64     if (isMenu) {
 65       // 找到对应资源菜单下的子菜单(按钮)map, 页面对应button,menuType-2
 66       const btns = filterBtnRoutes(state.menuTree, params).filter(x => x.menuType === 2)
 67 
 68       const flatBtns = flatten(btns)
 69       const btnPermission = flatBtns.map(x => x.buttonCode)
 70       commit('SET_BTN_PERMISSIONS', btnPermission)
 71     }
 72   },
 73 }
 74 
 75 
 76 
 77 // 路由卫士:跳转前的操作
 78 router.beforeEach(async (to, from, next) => {
 79   const appState = store.state.app
 80   nProgress.start()
 81   if (to.meta.system) {
 82     next()
 83   } else {
 84     if (appState.token) {
 85       if (!appState.userInfo?.username) {
 86         await store.dispatch('app/getUserInfo')
 87       }
 88       if (appState.menuTree.length === 0) {
 89         await store.dispatch('app/getMenuTree')
 90       }
 91       // 跳转路由,获取路由下有权限的按钮
 92       store.dispatch('app/getBtnPermissions', to.path)
 93       if (from.meta.cache) {
 94         store.commit('cache/ADD_CACHEDVIEW', from)
 95       }
 96       next()
 97     } else {
 98       next(`/login?redirect=${to.path}`)
 99     }
100   }
101 })
102 
103 
104 
105 // 全局判断是否有按钮权限
106 app.config.globalProperties.$hasBtnPermission = key => {
107   const btnPermissions = store.state.app.btnPermission
108   return key ? btnPermissions.includes(key) : false
109 }
110 
111 
112 // 展示有权限的按钮
113 if="$hasBtnPermission('add')">新增
114 if="$hasBtnPermission('edit')">编辑
115 if="$hasBtnPermission('delete')">删除
116 
117 // 侧边或顶部导航菜单,直接根据接口返回的有权限的数据循环出来