前言
在一個項目中,一些功能會涉及到重要的數據管理,為了確保數據的安全,我們會在項目中加入權限來限制每個用戶的操作。作為前端,我們要做的是配合后端給到的權限數據,做頁面上的各種各樣的限制。
需求
因為這是一個工作上的業務需求,所以對於我來說主要有兩個地方需要進行權限控制。
第一個是側邊菜單欄,需要控制顯示與隱藏。
第二個就是頁面內的各個按鈕,彈窗等。
流程
-
如何獲取用戶權限?
后端(當前用戶擁有的權限列表)-> 前端(通過后端的接口獲取到,下文中我們把當前用戶的權限列表叫做 permissionList)
-
前端如何做限制?
通過產品的需求,在項目中進行權限點的配置,然后通過 permissionList 尋找是否有配置的權限點,有就顯示,沒有就不顯示。
-
然后呢?
沒了。
當我剛開始接到這個需求的時候就是這么想的,這有什么難的,不就獲取 permissionList 然后判斷就可以了嘛。后來我才發現真正的需求遠比我想象的復雜。
真正的問題
上面的需求有提到我們主要解決兩個問題,側邊菜單欄的顯示 & 頁面內操作。
假設我們有這樣一個路由的設置(以下只是一個例子):
import VueRouter from vue-router /* 注意:以下配置僅為部分配置,並且省去了 component 的配置 */ export const routes = [ { path: / , name: Admin , label: 首頁 }, { path: /user , name: User , label: 用戶 , redirect: { name: UserList }, children: [ { path: list , name: UserList , label: 用戶列表 }, { path: group , name: UserGroup , label: 用戶組 , redirect: { name: UserGroupList }, children: [ { path: list , name: UserGroupList , label: 用戶組列表 }, { path: config , name: UserGroupConfig , label: 用戶組設置 } ] } ] }, { path: /setting , name: Setting , label: 系統設置 }, { path: /login , name: Login , label: 登錄 } ] const router = new VueRouter({ routes }) export default router
其中前兩級路由會顯示在側邊欄中,第三級就不會顯示在側邊欄中了。
頁面內操作的權限設置不需要考慮很多其他東西,我們主要針對側邊欄以及路由進行問題的分析,通過分析,主要有以下幾個問題:
-
什么時候獲取 permissionList,如何存儲 permissionList
-
子路由全都沒權限時不應該顯示本身(例:當用戶列表和用戶組都沒有權限時,用戶也不應該顯示在側邊欄)
-
默認重定向的路由沒有權限時,應尋找 children 中有權限的一項重定向(例:用戶路由重定向到用戶列表路由,若用戶列表沒有權限,則應該重定向到用戶組路由)
-
當用戶直接輸入沒有權限的 url 時需要跳轉到沒有權限的頁面或其他操作。(路由限制)
下面我們針對以上問題一個一個解決。
什么時候獲取權限,存儲在哪 & 路由限制
我這里是在 router 的 beforeEach 中獲取的,獲取的 permissionList 是存放在 vuex 中。
原因是考慮到要做路由的限制,以及方便后面項目中對權限列表的使用,以下是實現的示例:
首先我們加入權限配置到 router 上:
// 以下只展示部分配置 { path: /user , name: User , label: 用戶 , meta: { permissions: [ U_1 ] }, redirect: { name: UserList }, children: [ { path: list , name: UserList , label: 用戶列表 , meta: { permissions: [ U_1_1 ] } }, { path: group , name: UserGroup , label: 用戶組 , meta: { permissions: [ U_1_2 ] }, redirect: { name: UserGroupList }, children: [ { path: list , name: UserGroupList , label: 用戶組列表 , meta: { permissions: [ U_1_2_1 ] } }, { path: config , name: UserGroupConfig , label: 用戶組設置 , meta: { permissions: [ U_1_2_2 ] } } ] } ] }
可以看到我們把權限加在了 meta 上,是為了更簡單的從 router.beforeEch 中進行權限判斷,權限設置為一個數組,是因為一個頁面可能涉及多個權限。
接下來我們設置 router.beforeEach :
// 引入項目的 vuex import store from @/store // 引入判斷是否擁有權限的函數 import { includePermission } from @/utils/permission router.beforeEach(async (to, from, next) => { // 先判斷是否為登錄,登錄了才能獲取到權限,怎么判斷登錄就不寫了 if (!isLogin) { try { // 這里獲取 permissionList await store.dispatch( getPermissionList ) // 這里判斷當前頁面是否有權限 const { permissions } = to.meta if (permissions) { const hasPermission = includePermission(permissions) if (!hasPermission) next({ name: NoPermission }) } next() } } else { next({ name: Login }) } })
我們可以看到我們需要一個判斷權限的方法 & vuex 中的 getPermissionList 如下:
// @/store export default { state: { permissionList: [] }, mutations: { updatePermissionList: (state, payload) => { state.permissionList = payload } }, actions: { getPermissionList: async ({ state, commit }) => { // 這里是為了防止重復獲取 if (state.permissionList.length) return // 發送請求方法省略 const list = await api.getPermissionList() commit( updatePermissionList , list) } } }
// @/utils/permission import store from @/store /** * 判斷是否擁有權限 * @param {Array<string>} permissions - 要判斷的權限列表 */ function includePermission (permissions = []) { // 這里要判斷的權限沒有設置的話,就等於不需要權限,直接返回 true if (!permissions.length) return true const permissionList = store.state.permissionList return !!permissions.find(permission => permissionList.includes(permission)) }
重定向問題
轉載於:https://www.cnblogs.com/duanlibo/p/12033858.html
https://blog.csdn.net/ningqiugu/article/details/83591112