以前寫過一篇大話權限中心的PHP架構之道,主要是從軟件工程角度介紹,如何經過編碼規範、依賴管理、數據源架構、事務處理、單元測試等技術,來保障權限系統的高可用,並未真正的涉及這套系統的架構。php
今天準備從設計細節上分享一二。編程
望各位看官,心有「空杯」,帶着「問題」一探究竟。架構
這裏仍是尤其的重要,由於他是整套系統設計的根基。app
因此殘忍的從上一篇中複製了一遍。。。單元測試
RBAC認爲權限受權其實是Who、What、How的問題。在RBAC模型中,who、what、how構成了訪問權限三元組,也就是「Who對What(Which)進行How的操做」。測試
Who:權限的擁用者或主體(如Principal、User、Group、Role、Actor等等)this
What:權限針對的對象或資源(Resource、Class)。編碼
How:具體的權限(Privilege,正向受權與負向受權)。url
Operator:操做。代表對What的How操做。也就是Privilege+Resourcespa
Role:角色,必定數量的權限的集合。權限分配的單位與載體,目的是隔離User與Privilege的邏輯關係.
權限系統的本質就是這個模型(我的觀點勿噴)。咱們在此核心思想上,抽象了兩個新概念。
應用建模、權限自治
下面將從如下4個層面展開介紹。
應用建模
業務場景
權限管理
鑑權設計
系統架構上支撐權限系統靈活配置,不僵硬字段,不僵硬行爲,基於各類業務權限管控的特徵靈活設計。
公式一枚:應用=資源+行爲+角色
簡單點說,就是要管控資源的屬性和行爲。
好比要管控菜單,屬性就包括菜單ID、菜單名稱、菜單URL、菜單ICON、上級菜單ID等,行爲就包括訪問、受權等。(菜單權限)
好比要管控城市,屬性就包括區域ID、區域名稱、區域代碼、所屬區域ID等,行爲就包括訪問、受權等。(區域權限)
好比要管控CMS,字段就包含頁面ID、頁面名稱等,行爲就包括訪問、受權、編輯、重置等。(CMS數據權限)
按照慣性的思惟,這裏就是3張資源表對應角色表,同時還有3張資源角色關係表,換而言之,就是有多少資源須要管控就有多少張表(又是我的觀點,勿噴)。
慣性的思惟,兩個痛點。
每一種資源都要獨立存儲。
每一種資源都要有一套Form排版&交互&存儲實現。
爲了解決這個問題,咱們作了如下的設計。
任意資源的字段,均可以抽象成以下幾類。
資源映射字段(mapField)
資源節點字段(treeFiled)
資源系統字段(systemFields)
資源表單字段(columns)
資源行爲字段(privileges)
舉個栗子:菜單資源。
class menu extends app { public static $appMapField = 'url'; public static $appTreeField = 'name'; public static $columns = array( array( 'id' => 'id', 'label' => '菜單ID', 'type' => 'input', 'format' => 'int', 'option' => array() ), array( 'id' => 'name', 'label' => '菜單名稱', 'type' => 'input', 'format' => 'string', 'option' => array() ) ); public static $privileges = array( array( 'id' => 'access', 'name' => '訪問' ) ); public static $systemFields = array('id', 'parent_id'); }
表單在網頁中主要負責數據採集功能。一個表單有三個基本組成部分:
表單標籤;
表單域,包含了文本框、密碼框、隱藏域、多行文本框、複選框、單選框、下拉選擇框和文件上傳框等;
表單按鈕。
常規工做是靜態表單。
設計動態表單模型,基本的思路應該是數據和表現顯示的分離。拋開表現層,一個表單包含的若干個字段和填寫的數據。所謂動態,就是這些字段名稱可能改變,數量可能有增減。
經過資源的columns字段控制表現層。
經過資源的數據字段控制數據層。
經過這種模式,任意資源的Form排版&交互&存儲都動態實現了。
資源表對應的Schema以下:
字段名稱 | 字段備註 |
---|---|
應用ID | / |
資源ID | / |
資源父ID | / |
資源Data | JSON |
經過反射API,獲取當前應用的資源存儲插件(資源Data字段)。
app::find($params['app_id'])->getResoucePlugin()->save($params['data']);
經過資源基類作數據存儲的統一封裝。
public function save() { $this->beforeSave($this->attributes); } protected function beforeSave() { //check attributes }
很顯然資源Data字段,不能很好的完成單資源行爲鑑權的任務。
設計上引入了資源映射字段,每當資源變動時,觸發addMap
,會同步字段信息到資源映射關係表中(資源的語義化索引)。
舉幾個栗子,方便你們理解這個字段:
好比菜單類應用,映射字段就是菜單連接。
好比數據類應用,映射字段就是數據ID。
public function addMap() { if ($this->map) { //sync map field } else { //create map field } }
應用建模,相對來講是一個較技術的話題,換個方向,下面來和你們聊一聊系統的業務場景。
系統架構上支撐多種業務形態的權限管控。
說到權限,大多數應用場景都會想到菜單權限,然而咱們也不例外,菜單類的應用,就是生產的第一個實例。
舉個栗子:A系統/菜單權限應用
字段
菜單ID、菜單名稱、菜單連接、菜單上級ID
行爲
訪問、受權
數據類應用,相對於菜單類型來講,更關注的是,對某一行數據的行爲控制,行爲是多樣的。
舉個栗子:A數據/數據權限應用
字段
數據ID、數據名稱
行爲
訪問、受權、編輯、刪除、新增、重置、導出、導入
表單類應用,在2B的系統中,權限設計尤其重要。
舉個栗子:A確認單/表單權限應用
字段
模塊ID、模塊名稱(行程模塊、供應商模塊、訂單模塊、財務模塊)
行爲
訪問、受權、只讀、可寫、隱藏
總結一下權限的業務場景:
菜單類:單資源的單行爲(可否」行爲「當前「資源」)
數據類:單資源的多行爲
表單類:多資源的多行爲
小夥伴們,大家的業務場景能實現嗎?(留言吧)
接下來講說權限管理中的一些設計之道。
設計上參考JIRA,當前應用的管理者主導當前應用的權限生態。
資源的增刪改查
角色的增刪改查
資源字段定義
資源行爲定義
資源行爲的角色賦予
系統中給每一種資源都天生賦予一種系統行爲叫作「受權」。
任意資源節點的角色行爲賦予,都由擁有該資源節點受權行爲的角色去分配。
兩個維度受權,方便檢索,也方便配置。
基於角色+行爲,選擇資源。
基於資源+行爲,選擇角色。
^^^^^^^^
下一個階段將會支持默認權限的配置,非應用內的角色,也一樣能夠享有應用內的部分資源的部分行爲的權限。
最後簡單說下,鑑權接口的設計。
U、R、P、S分別表示用戶集合、角色集合、許可權集合和會話集合。
PA P×R表示許可權與角色之間多對多的指派關係。
UA U×R表示用戶與角色之間多對多的指派關係。
公式一枚:S=UA ∩ PA
統稱爲資源樹接口。
舉個栗子:R角色在A應用中擁有P行爲的資源。
統稱爲行爲鑑權接口。
舉個栗子:R角色在A應用中是否擁有R資源的P行爲。
權限系統一直以來是咱們應用系統不可缺乏的一個部分,若每一個應用系統都從新對系統的權限進行設計,以知足不一樣系統用戶的需求,將會浪費咱們很多寶貴時間,因此花時間來設計一個相對通用的權限系統是頗有意義的。
設計一個相對通用的系統是頗有意義的。(不只僅是權限)
多交流,多分享,書寫更好的代碼。
享受編程和技術所帶來的快樂。