前、後端分離權限控制設計和實現思路

點擊上方“朱小廝的博客”,選擇“設爲星標”

後臺回覆"加羣",加入新技術

來源:8rr.co/9QUT

簡述

近幾年隨着react、angular、vue等前端框架興起,前後端分離的架構迅速流行。但同時權限控制也帶來了問題。

網上很多前、後端分離權限僅僅都僅僅在描述前端權限控制、且是較簡單、固定的角色場景,滿足不了我們用戶、角色都是動態的場景。且僅僅前端進行權限控制並不是真正意義的權限控制,它只是減少頁面結構暴露、增強用戶體驗的功效。

場景

系統爲後臺管理系統,包含了用戶創建、用戶登錄、用戶管理自己的資源。用戶經常會新增、刪除,也可以根據工作情況隨時調整頁面、功能權限,所以採用用戶-角色-頁面權限方案實現。

爲什麼不行:

  1. 根據前端路由表顯示左側菜單,但vue-router的路由表主要爲了組織代碼,經常我們所需要的菜單並非一致。比如某個前端路由a子路由有b、c,但菜單中我們想要直接一級菜單就顯示b、c或者將b、c各放到其他菜單下。所以這種非常不靈活。

  2. 一個路由是菜單還是頁面?是否需要顯示到菜單中?是否驗證權限?哪個角色或者用戶擁有權限?這些都需要寫到前端路由裏面,一旦有任何權限變動就要大量調整代碼。

  3. 如果權限寫死在前端,那麼角色或者用戶必須已知且固定不變。比如頁面1的meta增加屬性標識可訪問的角色爲a和b

頁面

一個頁面即一個前端頁面,比如首頁、用戶管理頁、資源管理頁等。

基本思路爲:前端路由保持不變,數據庫存儲菜單結構、頁面權限控制(可以直接做成一個頁面來方便管理)等,前端根據數據庫中的菜單結構和權限信息來渲染一個菜單出來並只顯示其有權限的菜單,並在路由守衛中進行權限控制防止手動輸入path越權打開頁面

1、前端路由(vue-router)中需要正常創建頁面及路由。

2、數據庫存儲菜單結構和頁面權限信息,

  1. 菜單(目錄、非內容頁)可以自己創建,不必要求前端路由中有,因爲這是指菜單的可視化的組織結構

  2. 頁面(內容頁)必須是前端路由中已有頁面,因爲這是用戶需要訪問的內容。

  3. 菜單和頁面組成上下級關係,一級可以是菜單也可以是內容頁,內容頁也可以放在菜單下,不可見的內容頁也可以放在一個普通內容頁下,這樣理論(需要頁面菜單樣式支持)可以組成無限級菜單。麪包屑導航也根據此層級遞歸查詢得到。

  4. 菜單和頁面的基本屬性包括title(對應路由title)、name(對應路由name)、path(對應路由path)、父級、類型(菜單/頁面)、是否可見(左側菜單欄是否顯示:部分頁面可能是頁面內的鏈接進去)、是否需要驗證權限(部分頁面比如首頁無需驗證權限大家都可以進入)

  5. 不需要控制權限且不需要顯示到左側菜單的路由這裏可以不進行管理,比如404頁面等

3、前臺打開後獲取獲取數據庫的所有菜單、頁面及結構,根據是否登錄、是否需要驗證權限等進行控制,或無權限跳轉至登錄頁

4、用戶登錄成功後,再獲取用戶對應的的頁面權限列表,使用上一步獲得的所有頁面、結構和用戶擁有權限的列表渲染出一個菜單,只包含此用戶擁有權限的,提升用戶體檢,避免顯示大量用戶不能訪問的菜單影響使用和不必要的功能暴露。

5、路由守衛中根據上一步獲得的權限列表判斷每個跳轉,無權限可返回404或無權限頁面,防止用戶手動輸入path越權訪問

頁面管理:

頁面編輯:

功能

部分功能有事需要單獨控制權限,比如用戶管理頁面可能允許多個角色查看,但是其中的"創建用戶"功能只允許某一個角色使用,那麼僅僅使用頁面權限是不夠。所以需要細粒度的功能權限控制。

網上的方案都是說:根據資源控制增、刪、改、查等等,比如針對用戶就是用戶的創建、修改、刪除、查詢等。但是在我的實際使用中發現並不切合實際,最起碼對像我這種管理後臺,資源並不單純的增刪改查,可能有其他地方的其他操作中也會對此用戶資源造成影響,比如禁用、刪除角色也要禁用、刪除用戶,那麼這個權限到底屬於角色的權限還是屬於用戶的權限,或者後臺又改了,角色又影響了其他資源或者不再對用戶進行操作,都會影響權限控制。

所以更合理的方法應該爲將每個功能單獨進行控制並和頁面進行關聯,且不限定必須是增、刪、改、查四種,可以任意定製,只需要與前後端開發約定一個唯一的標識即可。

如上的例子中,用戶管理頁面下有用戶各種功能,角色管理頁面中也有個角色禁用、刪除功能,可以分別定義標識爲roledisable、roledelete,如果擁有roledelete權限即可,即使沒有userdelete權限,也可以直接刪除用戶,否則就不要給其role_delete權限。

用戶登錄後,從數據庫獲取其所擁有的的權限列表並存入vuex,包含頁面和功能對應關係,例如頁面name爲user:{user: ['userdelete', 'userquery']},頁面中根據刪除按鈕可以v-if="hasPermission('user_delete')"判斷即可

頁面功能管理:

獲取用戶擁有的權限:

角色

一個角色類似於一個身份或崗位,每個角色有自己的權限範圍。

  1. 一個角色可以擁有多個頁面權限。

  2. 一個角色可以擁有多個功能權限。

角色管理:

角色分配權限:

用戶

用戶可以創建、刪除,一個用戶隨時可能變更工作內容,或者身兼數職,所以可以爲其分配一個或者多個角色,他擁有的角色的權限就是他的權限。此時已經可以打通權限前端的權限分配,用戶-角色-頁面權限、功能權限。

用戶管理:

用戶分配角色:

前端效果

前端頁面菜單效果:

後端權限

傳統前後端不分離的情況下,路由都在後端統一管理,簡單的方法比如用戶管理頁面/user/那麼他裏面使用的接口都使用/user/add、/user/delete等相同前綴,那麼只要判斷用戶擁有/user/權限就可以訪問/user/*所有接口。

前後端分離後面臨的問題:

  1. 前、後端分別有自己的路由,且一個頁面會同時調後端多個不同模塊下的接口,這樣一來就無法通過以上傳統方式判斷權限。

如此一來嗎,就需要有前端頁面到後端接口的管理,明確一個頁面會調用哪幾個接口。這樣當授權用戶頁面時,系統就可以根據此關係推斷哪些接口具有權限。

接口

方案:

  1. 需要控制權限的接口進行上傳管理(可以做成管理頁面)

  2. 每個頁面和功能可以關聯多個接口,比如用戶頁面關聯了用戶查詢接口和用戶編輯接口,用戶刪除功能關聯用戶刪除接口

  3. 後端對請求的路徑進行判斷,用戶->角色->頁面/功能->接口,擁有接口權限即允許訪問

  4. 前後端分團隊開發,不容易一一對照,且前端有自己的路由(此路由受限於代碼組織結構)等等,無法使用傳統方式簡單處理

  5. 相同的接口可能會被前端多個頁面多次利用

接口管理:

頁面關聯接口、功能關聯接口:

請求的接口無權限時:

接口後端權限控制

後端控制其實很簡單,只要前面管理功能做好即可,基本邏輯爲:

  1. 用戶訪問接口

  2. 判斷用戶和當前path,根據用戶->角色->頁面/功能->接口 得到當前用戶有權限的接口列表與當前path相比

  3. 若無權限(某些接口只需要登錄就能訪問的,比如獲取用戶姓名信息的需要排除在外)則直接返回失敗,前端全局捕獲後給出無權限提示

數據庫表示例

紅色表爲實體表,藍色表爲關聯關係表。基本爲用戶->角色->頁面/功能->後端接口

想知道更多?描下面的二維碼關注我

後臺回覆”加羣“獲取公衆號專屬羣聊入口

【精彩推薦】

點個在看少個 bug ????

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章