組織架構(gòu)
1.需求點
- 查詢某個組織下面的所有用戶(包括所有下級組織)
- 查詢某個組織下面的所有下級組織
- 查詢用戶所在的組織
- 獲取整個組織結(jié)構(gòu),方便生成樹形數(shù)據(jù)結(jié)構(gòu)
2.組織表
相關(guān)的必要字段如下:
- id,主鍵ID
- pid,父級組織id
- tree,當前節(jié)點的所有父級組織,假設(shè)當前組織的父級id為2,2的父級id為1,則tree的值為:1,2
3.用戶表
相關(guān)的必要字段如下:
- department,所在的組織id。
4.相關(guān)SQL
4.1 查詢用戶所在的組織
SELECT * FROM `department` `a`, INNER JOIN user `b` ON `a`.`id` = `b`.`department` WHERE b.id = "用戶ID";
4.2 獲取指定組織下的所有組織
SELECT * FROM `department` WHERE FIND_IN_SET( "組織ID", `tree` )
4.3 查詢組織下面的所有用戶
SELECT * FROM `user` `a` INNER JOIN `department` `b` ON `a`.`department` = `b`.`id` WHERE ( a.department IN (( SELECT id FROM `department` WHERE ( FIND_IN_SET( "組織ID", `tree` ) OR id = "組織ID" ) )) )
角色與權(quán)限
通常情況下有兩種方式可以控制用戶權(quán)限,一種是通過用戶角色(Role)來控制權(quán)限,另一種是通過更細致的權(quán)限(Operation)來直接指定某個用戶可以進行哪些行為。
1.角色
不同的角色可以訪問的功能集合(可訪問的頁面)不同,創(chuàng)建角色時設(shè)置角色可訪問的頁面。
前后端分離的模式下,將角色的可訪問路由傳遞給前端,由前端動態(tài)加載路由。
角色=可訪問的頁面+可操作的權(quán)限 ,按照這個進行設(shè)計,每個操作和頁面關(guān)聯(lián)了指定的一些接口
- RBAC0/RBAC1/RBAC2/RBAC3種,基于角色的意思是在系統(tǒng)中創(chuàng)建名為角色的橋梁,將客體的權(quán)限直接與角色進行關(guān)聯(lián),訪問主體則通過被賦予的角色來訪問與角色相關(guān)聯(lián)的客體。
- RBAC0:最核心的模型,其主體角色、客體能夠以多對多的關(guān)系進行關(guān)聯(lián):
- RBAC1:引入角色繼承,將角色分為不同等級,且角色間存在上下級關(guān)系,同時支持角色間的繼承
- RBAC2:在RBAC0的基礎(chǔ)上約束控制角色,在角色被賦予客體權(quán)限及主體在獲得角色時應(yīng)遵循強制性約束規(guī)則,包括:互斥角色、角色被賦予主體數(shù)量約束、獲得上級角色需先獲得下級角色等
- RBAC3: 覆蓋RBAC0/RBAC1/RBAC2所有功能。
參考:https://blog.csdn.net/weixin_42149145/article/details/112575531
2.動態(tài)路由
系統(tǒng)初始化的時候,只加載一些初始的路由頁面(比如登錄頁面),登錄成功后,從后臺請求對應(yīng)權(quán)限的路由表,然后通過router.addRoute動態(tài)添加路由。
for (let x of res) {
router.addRoute(x)
}
3.架構(gòu)設(shè)計
前端可以設(shè)計如下一些功能,以Vue為例:
- 鑒權(quán)函數(shù),auth
- 鑒權(quán)指令,v-auth
- 鑒權(quán)組件,<v-auth>
后端則按照如下規(guī)則進行權(quán)限判斷:
- 角色 -> 獲取可訪問的頁面 -> 獲取頁面相關(guān)的權(quán)限 -> 獲取權(quán)限關(guān)聯(lián)的后端接口
- 刪除權(quán)限(總表)時,外鍵同步刪除頁面和權(quán)限的關(guān)聯(lián),外鍵又同步刪除角色和權(quán)限的關(guān)聯(lián),外鍵同步刪除權(quán)限和接口的關(guān)聯(lián)
- 刪除路由(總表)時,外鍵同步刪除權(quán)限,外鍵同步刪除頁面和權(quán)限的關(guān)聯(lián),外鍵又同步刪除角色和權(quán)限的關(guān)聯(lián),外鍵同步刪除權(quán)限和接口的關(guān)聯(lián)
- 刪除角色和頁面時,強制存在子元素時不可刪除(邏輯上限制以及數(shù)據(jù)庫外鍵限制)
- 父角色刪除一個可訪問的頁面時,同步刪除所有子角色的頁面,同時要刪除整個角色樹上跟這個頁面關(guān)聯(lián)的所有權(quán)限
- 父角色刪除一個權(quán)限時,同步刪除所有角色樹上子角色的權(quán)限。
- 新增頁面或者權(quán)限時,同步給系統(tǒng)管理員新增該頁面和權(quán)限。
4.問題總結(jié)
- 展示子角色的可選頁面時,應(yīng)該拉取它的父角色可訪問頁面
- 用戶不可以修改自己的角色。
- 但是可以獲取不包括自己角色的角色樹
- 子角色新增、修改的頁面,必須在父角色的頁面集合內(nèi)。
- 路由修改父級路由時,不能選擇自己
- 刪除,新增,修改角色時,都需要判斷用戶有沒有權(quán)限
- 刪除,新增,修改指定角色的頁面時,都需要判斷權(quán)限
- 獲取權(quán)限列表,要綜合父角色的已有權(quán)限和當前角色擁有的頁面
- 刪除角色時,判斷有沒有該角色的用戶,有的話不允許刪除
5.組織和用戶
- 移動一個組織,要修改它下面所有組織的組織樹
- 移動一個頁面,要修改它下面所有頁面的頁面樹
- 修改組織和頁面的父級時,不能選擇自身或下級組織、頁面
- 上級用戶修改、刪除下級用戶時,要先從組織和角色兩方面去判斷
- 刪除用戶時,假如用戶賬號內(nèi)還有客戶,則不允許刪除。
- 刪除組織時,組織內(nèi)還有用戶,也不允許刪除
- 刪除組織時,如果有子組織則不允許刪除
6.權(quán)限判斷
設(shè)計到權(quán)限判斷的操作:新增、修改、刪除、查詢
判斷用戶對一個客戶是否擁有權(quán)限
- 是不是自己的客戶
- 是不是自己所在組織或下級組織的用戶的客戶
- 有沒有處理下級用戶的客戶的權(quán)限
判斷用戶有沒有操作另一個用戶的權(quán)限
- 是不是自己所在組織或下級組織的用戶
- 有沒有處理下級組織用戶的權(quán)限
判斷用戶有沒有操作一個組織的權(quán)限
- 是不是自己所在組織或下級組織
- 有沒有操作下級組織的權(quán)限
角色的上下級關(guān)系,只能用于用戶添加和用戶角色修改的范圍限制,單純的角色上下級關(guān)系不能作為權(quán)限判斷的條件
系統(tǒng)分庫模式
1.思考點
多公司分庫模式下,多出來的一些思考點:
主表(公共表):
- 公司表
- 路由表
- 權(quán)限表
公司表:
- 角色與權(quán)限關(guān)聯(lián)
- 角色與路由的關(guān)聯(lián)
適配修改:
- 新增一個權(quán)限,是否是系統(tǒng)管理員。
- 修改角色與權(quán)限、角色與路由的關(guān)聯(lián),通過跨庫外鍵去約束。
- 新增權(quán)限時,可選是否應(yīng)用到所有公司管理員的角色上。
- 操作角色權(quán)限、組織架構(gòu)判斷操作的是哪個公司
2.跨公司操作
管理員跨公司操作時,需要處理的細節(jié):
- 角色切換,如何平滑處理不同公司的角色權(quán)限的問題?
- 組織切換,如果平滑處理不同公司組織架構(gòu)的問題?
- 公司切換,切換公司之后,需要判斷是否具有權(quán)限以及切換對應(yīng)的連接池
總結(jié):切換公司之后,權(quán)限判斷走本身所在公司的角色,部門修改為所選公司的根節(jié)點,角色修改為根角色(權(quán)限不同步改變)
- 根據(jù)中間件執(zhí)行的先后順序,接口權(quán)限判斷的中間件會先于公司切換的中間件運行,在接口權(quán)限判斷的階段就緩存好用戶權(quán)限,之后不再重新初始化。
問題記錄
1.客戶查詢
查詢當前用戶的下級用戶的所有客戶的訂單數(shù)據(jù),查詢出權(quán)限范圍內(nèi)的去重后的客戶ID集合,然后再去通過in判斷客戶是否在這個集合內(nèi)??蛻魯?shù)量越來越多時,如何處理?
客戶的更新頻率不會很高,通過建表,緩存指定用戶的客戶ID,并實時更新,然后將這個表用于IN查詢