天天看點

如何優雅的在 vue 中添權重限控制

在一個項目中,一些功能會涉及到重要的資料管理,為了確定資料的安全,我們會在項目中加入權限來限制每個使用者的操作。作為前端,我們要做的是配合後端給到的權限資料,做頁面上的各種各樣的限制。

因為這是一個工作上的業務需求,是以對于我來說主要有兩個地方需要進行權限控制。

第一個是側邊菜單欄,需要控制顯示與隐藏。

第二個就是頁面内的各個按鈕,彈窗等。

如何擷取使用者權限?

後端(目前使用者擁有的權限清單)-> 前端(通過後端的接口擷取到,下文中我們把目前使用者的權限清單叫做 permissionList)

前端如何做限制?

通過産品的需求,在項目中進行權限點的配置,然後通過 permissionList 尋找是否有配置的權限點,有就顯示,沒有就不顯示。

然後呢?

沒了。

當我剛開始接到這個需求的時候就是這麼想的,這有什麼難的,不就擷取 permissionList 然後判斷就可以了嘛。後來我才發現真正的需求遠比我想象的複雜。

上面的需求有提到我們主要解決兩個問題,側邊菜單欄的顯示 & 頁面内操作。

假設我們有這樣一個路由的設定(以下隻是一個例子):

其中前兩級路由會顯示在側邊欄中,第三級就不會顯示在側邊欄中了。

頁面内操作的權限設定不需要考慮很多其他東西,我們主要針對側邊欄以及路由進行問題的分析,通過分析,主要有以下幾個問題:

什麼時候擷取 permissionList,如何存儲 permissionList

子路由全都沒權限時不應該顯示本身(例:當使用者清單和使用者組都沒有權限時,使用者也不應該顯示在側邊欄)

預設重定向的路由沒有權限時,應尋找 children 中有權限的一項重定向(例:使用者路由重定向到使用者清單路由,若使用者清單沒有權限,則應該重定向到使用者組路由)

當使用者直接輸入沒有權限的 url 時需要跳轉到沒有權限的頁面或其他操作。(路由限制)

下面我們針對以上問題一個一個解決。

我這裡是在 router 的 beforeEach 中擷取的,擷取的 permissionList 是存放在 vuex 中。原因是考慮到要做路由的限制,以及友善後面項目中對權限清單的使用,以下是實作的示例:

首先我們加入權限配置到 router 上:

可以看到我們把權限加在了 meta 上,是為了更簡單的從 router.beforeEch 中進行權限判斷,權限設定為一個數組,是因為一個頁面可能涉及多個權限。 接下來我們設定 router.beforeEach :

我們可以看到我們需要一個判斷權限的方法 & vuex 中的 getPermissionList 如下:

以上我們解決了路由的基本配置與權限如何擷取,怎麼限制路由跳轉,接下來我們要處理的就是重定向問題了。

這一點可能和我們項目本身架構有關,我們項目的側邊欄下還有子級,是以下圖中的 tab 切換展現的,正常情況當點選藥品管理後頁面會重定向到入庫管理的 tab 切換頁面,但當入庫管理沒有權限時,則應該直接重定向到出庫管理界面。

如何優雅的在 vue 中添權重限控制

是以想實作以上的效果,我需要重寫 router 的 redirect,做到可以動态判斷(因為在我配置路由時并不知道目前使用者的權限清單),然後我檢視了 vue-router 的文檔,發現了 redirect 可以是一個方法,這樣就可以解決重定向問題了。

vue-router 中 redirect 說明 ,根據說明我們可以改寫 redirect 如下:

雖然問題解決了,但是發現這樣寫下去很麻煩,還要修改 router 的配置,是以我們使用一個方法生成:

然後我們就可以改寫為:

這樣稍微簡潔一些,但我還是需要一個一個路由去修改,是以我又寫了一個方法來遞歸 router 配置,并重寫他們的 redirect:

這樣我們隻需要在最外層的 router 配置加上這樣一層函數就可以了:

當然這樣寫還有一個好處,其實你并不需要設定 redirect,這樣會自動重定向到 children 的第一個有權限的路由

我們的項目使用的是根據路由的配置來生成側邊欄的,當然會加一些其他的參數來顯示顯示層級等問題,這裡就不寫具體代碼了,如何解決側邊欄 children 全都無權限不顯示的問題呢。

這裡我的思路是,把路由的配置也一同更新到 vuex 中,然後側邊欄配置從 vuex 中的配置來讀取。

由于這個地方涉及修改的東西有點多,而且涉及業務,我就不把代碼拿出來了,你可以自行實驗。

以上我們解決了大部分權限的問題,那麼還有很多涉及到業務邏輯的權限點的部署,是以為了團隊中其他人可以優雅簡單的部署權限點到各個頁面中,我在項目中提供了以下幾種方式來部署權限:

通過指令 v-permission 來直接在 template 上設定

通過全局方法 this.$permission 判斷,因為有些權限并非在模版中的

這裡要注意,為了 $permission 方法的傳回值是可被監測的,判斷時需要從 this.$store 中來判斷,以下為實作代碼:

以下為指令的實作代碼(為了不與 v-if 沖突,這裡控制顯示隐藏通過添加/移除 className 的方式):

針對之前的問題,有以下的總結:

router.beforeEach 擷取,存儲在 vuex。

子路由全都沒權限時不應該顯示本身(例:當使用者清單和使用者設定都沒有權限時,使用者也不應該顯示在側邊欄)

通過存儲路由配置到 vuex 中,生成側邊欄設定,擷取權限後修改 vuex 中的配置控制顯示 & 隐藏。

通過 vue-router 中 redirect 設定為 Function 來實作

在 meta 中設定權限, router.beforeEach 中判斷權限。

以上就是我對于這次權限需求的大體解決思路與代碼實作,可能并不是很完美,但還是希望可以幫助到你 ^_^