許可權在我看來指的是某個使用者是否能夠訪問某個介面。對應到前端,即使某個使用者訪問了一個本不應該讓他看到的頁面,在訪問介面時不具備許可權,這樣即使進入了頁面,也不能看到相應的資料。但是我們前端要做的工作就是讓使用者在訪問這個頁面的時候,直接就收到提示,沒有許可權。
但現在許多專案中頁面路由都是由前端去管理了,如何做到這一點呢,接下來我就分享一下在過往專案中我所用的方案。
我寫了demo,上傳到了github上,地址為:admin-permission-demo
資料庫表是怎樣設計的
一開始與後端去對接這個需求的時候,我是感到很懵逼的,覺得無從下手。因為我根本就不知道許可權控制是怎麼去做的,也不知道許可權其實就是限制使用者對於介面的訪問。所以開始之前我覺得有必要說一下,許可權表是怎樣設計的。 我們專案中所使用的是 RBAC ,其實很簡單,就是有這麼三個東西:使用者、角色、許可權(資源)。圖我就懶得畫了,省事兒直接用一個別人畫好的圖。
這個許可權就是專案中的介面,意思就很明顯了。給角色規定了能夠訪問哪些介面,然後給使用者分配了角色。這樣就能控制使用者哪些介面能訪問,哪些介面不能訪問。
選單許可權與按鈕許可權
我們專案中許可權表的大概的樣子:
id | p_id | type | permission | name |
---|---|---|---|---|
主鍵ID | 父級ID | 型別:選單或按鈕 | 許可權標識 | 名稱 |
許可權又分為選單許可權和按鈕許可權,什麼意思呢?
比方說我們現在要開發一個頁面,叫做使用者管理,在使用者管理這個頁面會進行一些對使用者增刪查改的操作。我管這個使用者管理叫做選單許可權,它下面的增刪查改(介面)的操作叫做按鈕許可權。這些介面的p_id很顯然就是這個選單許可權的主鍵ID了。
[
{
p_id: '',
id: 1000,
name: '許可權管理',
type: 1, // 選單
permission: 'permission_manage',
children: [
{
p_id: 1000,
id: 1100,
name: '使用者管理',
type: 1, // 選單
permission: 'user_manage',
children: [
{
p_id: 110,
id: 1101,
name: '新增使用者',
type: 2, // 按鈕
}
...
]
}
]
}
]
複製程式碼
怎麼樣,這樣的資料結構是不是很熟悉,是不是就是管理系統中左側選單。這個 選單許可權,就是前端在做頁面訪問控制時所要用到的東西。這個資料結構只是我為了方便理解這樣寫的。 在我的專案中我向後端查詢到的許可權資料不長這個樣子,就是一個陣列,每一項是資料,沒有做分組操作(就是沒有children)。這樣前端拿到資料了之後就可以根據 type
去整合成選單許可權集合和按鈕許可權集合,方便了後續的使用。
前端程式碼去實現許可權控制
理解了許可權是怎麼設計的,接下來說說前端程式碼怎麼去實現。
我過往的專案中所使用的都是 react + antd + dva + typescript。其實前端所選用的技術是什麼並不重要,重要的是思路理解了,剩下的只是程式碼實現的不同。
首先我會要後端給我提供一個介面,查詢當前使用者的所有許可權。然後我會把它分為 選單許可權 和 按鈕許可權 用 redux
去管理。
渲染左側選單
首先是渲染左側選單。在專案中一般情況下會有一個專門的左側選單的配置檔案,在該檔案裡定義了選單的名字啊、圖示啊、頁面路徑等資訊。有些選單頁面是需要被許可權管理的,而有些則不需要。對於需要被許可權管理的頁面我會新增一個欄位叫做選單標識。
interface MenuDataItem {
name: string; // 選單名字
icon?: string;
path: string;
children?: Array<MenuDataItem>;
permission?: string; // 選單標識
}
const menuData: MenuDataItem[] = [...];
複製程式碼
專案中的左側選單,就會根據這個 menuData
被渲染出來。這裡的邏輯是首先看這個選單有沒有選單標識,如果沒有的話直接渲染。如果有選單標識的話,就看使用者是否具有這個選單許可權,有就渲染,沒有就不渲染。每個專案的結構肯定不同,我就不多貼程式碼了,重要的是思路,具體實現我寫了demo,傳到了github上,感興趣可以去看,這是地址:admin-permission-demo。
路由層面的控制
只管理了左側選單的渲染肯定是不夠的,需要在路由層面再去做控制。一般情況下專案中會有一份路由表,react
的話路由也是元件,在路由渲染的地方去做控制就行。vue
的話是全域性配置 router
的,在路由守衛中限制就行。同樣的,頁面對應選單路由,看使用者是否具有選單許可權,不具備就到提示許可權不夠頁面,具備就正常顯示頁面。
按鈕層面的控制
還是拿使用者管理來舉一個例子,增、刪、查、改。 可能使用者只具備 刪、查、改的許可權而不具備增的許可權。這時候在頁面中就不應該渲染 “新增使用者” 這樣的按鈕了,不然使用者資料輸入了半天,一發請求後端一校驗提示許可權不足就尷尬了,我都不能做這個操作,你還展現給我幹啥?
這時候去寫一個元件,叫啥不重要,就比如說叫 PermissionButton
把。react的話將原本按鈕作為 children 傳入該元件,vue 的話應該就是 <slot>
。然後該元件還接收一個 props
,它是一個陣列,就叫他 permissions
把。該陣列的每一項就是按鈕許可權標識,代表需要哪些許可權才能展示這個按鈕,或者也有可能具有其中一項就可以展示。在提供一個props
去控制把,值為 every 或者 some。every就是全都有才能展示,some就是具備其中一項就能展示。
然後就是去查使用者的 按鈕許可權 了。 具備了改元件就展示 原本元件,不具備就不展示就行了。
總結
這是我做後臺管理系統所積累的一點實踐把。如果大家有何更好的方案,或者覺得哪裡可以改進的歡迎交流。
對 vue 的使用者可能不太友好。因為demo是react實現的。但是我並不覺得這個方案在react和vue下有太大的差異。如果後面我在工作中有使用vue去做的機會,在更新一版使用vue的demo把。最重要的還是要去理解這個許可權,其實也是簡單的東西。希望能夠幫助到有需要的人。
具體實現肯定不是幾行程式碼能夠貼清楚的,程式碼怎麼實現也關係到具體的專案結構。
我提供了demo,上傳到了github上,地址為:admin-permission-demo。
demo也是根據我自己搭的管理系統模板做的,地址為:antd-admin