賈薇





摘要:在Ruby on Rails 5框架下,設計一個基于Web的權限管理方案,滿足粗粒度與細粒度結合的高自由度控制的要求。
關鍵詞:Web;權限控制;粗粒度;細粒度;Ruby on Rails 5
一個大型的信息系統均會具有許多功能和許多用戶,這些用戶處于不同的崗位、具有不同的級別,他們從信息系統中獲取信息與處理信息的職權亦不同,這就要求應用系統提供一種權限管理機制,控制各種用戶使用系統的權力訪問。[1]一個穩定可靠的權限管理方案,應該具備粗粒度與細粒度結合、高自由度、高擴展性等特點。
設計一個基于Web的信息系統權限管理方案,并在Linux系統中,使用Ruby on Rails 5框架實現,使其具有上述功能特定。
1 系統環境
測試環境為Ubuntu16.04操作系統,Ruby on Rails 5.2.3(以下簡稱RoR),mysql 5.7數據庫。
2 粗粒度權限管理
在RoR構架下,采用控制器(controller)加動作(action)的方式進行邏輯控制。控制器通常用來關聯一個特定的對象實例,如人員、車輛等;動作通常表示對對象實例的一個操作,如新建、編輯、刪除等;每一個訪問比如對應一個控制器和一個動作。這個特性非常容易用來對進行權限的粗粒度管理。
2.1 注冊控制器/動作
首先將系統的頂層菜單作為對象,可以新建、存儲及修改刪除。菜單對象沒有業務邏輯,僅用于對控制器進行歸納展示。
將控制器和動作也看做對象進行處理。一個控制器的源文件在上傳到服務器之后,并不會自動出現在菜單中,而是需要先注冊。一個控制器對象實例必然屬于一個菜單對象實例,且包含若干個動作對象實例。
當一個控制器對象注冊時,需要填入中文名稱和英文名稱。中文名稱用于菜單展示,英文名稱用于讀取源文件和訪問控制。如新建一個控制器對象,中文名為“組織機構”,英文名為“dept”,屬于菜單“用戶管理”。系統首先會去讀取文件名為dept_controller.rb的源文件,然后對其進行文本分析查找出所有方法名,并自動將方法注冊為動作;注冊過程可以自動完成,也可以進行人工干預定義更多的屬性,如中文名、對應的快捷方式、允許訪問的最低權限等級(level,后續詳細說明)等。
2.2 設置角色
角色管理界面中,可以看到當前已經注冊的所有菜單、控制器、動作,且按照結構排列成樹形選項。
被選中的項目按照一定的結構生成JSON格式字符串,并作為角色對象實例的authority屬性值進行持久化存儲。
需要注意的是,如果系統存在根管理員角色,應將其的authority屬性特別標識;使其自動獲得所有路徑的訪問權限,以減少不必要的前端操作。
2.3 生成權限字典
每一個角色應該有一個權限字典。權限字典按照該角色的authority屬性以一定結構生成一個Hash對象。其中包含了該角色可見的菜單項、可訪問的路徑、路徑的相關屬性等。為提高系統運行效率,權限字典在系統運行期間應常駐內存;可采用Redis等NoSQL方式進行存儲。
當系統啟動時,生成所有角色的權限字典;當對角色authority屬性進行修改后,應更新常駐內存的權限字典。
2.4 訪問控制
粗粒度權限管理的訪問控制,應配置在每一個控制器的before_action方法中,在登錄驗證之后進行。根據當前用戶的角色和當前控制器/動作,在相應權限字典中查找:如果當前角色的權限字典中有當前控制器/動作,且當前用戶的level等級不低于允許訪問該動作的level等級,則允許訪問;否則執行頁面重定向。
2.5 權限字典擴展
上述權限字典也可關聯至單個用戶。用戶可繼承角色的權限字典,也可單獨維護一個權限字典;用戶權限字典優先級應高于角色權限字典。
3 細粒度權限管理
細粒度的權限管理需要考慮到對象實例的某些特性。比如在樹狀結構的組織機構中,不同分支之間的權限需要隔離,上級機構對下級機構具有權限等。細粒度權限管理和業務邏輯密切關聯,需要針對性的設計。采用權限等級level與DNA鏈兩種方式可以解決大部分業務流程對細粒度權限管理的要求。
3.1 權限等級level
所有的對象模型均配置有屬性level,數據類型為整形,如有必要還應分為讀權限等級r_level和寫權限等級w_level。角色實例必須設置level,用戶實例繼承角色實例的level值,也可單獨設置。
當前用戶的level值保存在session中,記為session[:level]。
3.1.1 設置實例權限等級
對象實例的權限等級在創建的時候設置,不得大于創建用戶的權限等級。如當前用戶的權限等級為5,創建的對象實例權限等級最大為5。對于已知的對象,可在創建時設置權限等級默認值:如寫權限w_level等于當前用戶session[:level];讀權限r_level設為0,即所有用戶均可讀取。應控制r_level不得大于w_level。
3.1.2 讀權限
根據當前用戶session[:level]控制實例讀權限,可將session[:level]前置到SQL請求中,使用where(‘r_level <= ?’,session[:level])語句進行限制。也可在獲取到對象實例之后,將對象實例的r_level與session[:level]進行比較,如r_level>session[:level] == true 則返回錯誤。
3.1.3 寫權限
根據當前用戶session[:level]控制實例寫權限,應在持久化對象之前,將對象實例的w_level與session[:level]進行比較,如w_level>session[:level] == true 則返回錯誤;否則允許執行update或delete操作。
3.2 DNA鏈
DNA鏈在處理樹狀結構的權限控制時具有特別的優勢。比如在基于組織構架的權限控制中,DNA鏈可以很方便的解決跨部門隔離、上下級權限等問題。
3.2.1 構建DNA鏈
需要注意的是,一個對象根據業務邏輯,可能會有多條不同的DNA鏈,以對應不同的業務屬性。比如機構內部一份文檔,按所屬部門分類有一條DNA鏈記為dept_dna,按文檔主題分類有一條DNA鏈記為category_dna。以標識部門屬性的DNA鏈dept_dna為例進行說明。
對象實例A,屬于部門B,部門B是部門C的子部門。部門C的dna為’1-3’,部門B的id為8,則部門B的dna為’1-3-8’;對象實例A繼承部門B的dna,則實例A的dept_dna為’1-3-8’。以上流程為后臺自動生成,前端不可見。
3.2.2 用戶權限
如果業務邏輯要求按照部門細分權限,則應對每個用戶設定其所在部門dept_id和權限所在部門handle_dept_id;默認情況下,兩個屬性的值一致,也可人為修改;如用戶X屬于部門B,但其具有上級部門C的權限,則其dept_id為8,handle_dept_id為3。用戶登陸時將handle_dept_id值保存在session中,記為session[:handle_dept_id]。
3.2.3 訪問控制
用戶在對實例進行訪問時,可將session[:handle_dept_id] 前置到SQL請求中,使用where(‘INSTR(concat('-',dept_dna,'-'),?) > 0’,‘%-’ + session[:handle_dept_id].to_s + ‘-%’)語句進行限制。也可在持久化對象之前,將對象實例的dept_dna與session[:handle_dept_id]進行比較,如session[:handle_dept_id]存在于dept_dna鏈條中則允許執行update或delete操作。
4 職能崗位
現代機構組織中,傳統的科層職能式組織結構因其固有缺點,負面效應越來越明顯;適宜分工和綜合性復合型的多功能工作部門(崗位)將成為未來生產組織和管理組織發展的一個基本方向[2]。一人多崗、一崗多人、職位(角色)崗位分離的現象越來越普遍。這也對信息系統的權限控制提出了新的要求。
需要注意的是,以下通過職能崗位進行權限控制默認為允許,即不設置時不進行職能崗位控制。
4.1 定義崗位及賦權
崗位可通過中文名稱進行定義,應保證其唯一性和可讀性;中文名稱無法確保唯一性時,應編制崗位代碼作為唯一性標識。名稱、崗位代碼主要用于在源文件中設置崗位準入權限時使用。
每個用戶可能對應多個崗位,也可能沒有具體崗位,可按一定結構將當前用戶對應的崗位id組織為JSON格式字符串進行持久化存儲,并在登錄時保存在session中,記為session[:duty_ids]。
4.2 粗粒度控制
通過職能崗位進行粗粒度控制有兩種方式,一種是直接在源文件中固化,通過職能崗位的名稱或崗位代碼進行準入控制;一種是在控制器/動作注冊時,將允許訪問的職能崗位定義到動作中。具體實現方法不再贅述。
4.3 細粒度控制
通過職能崗位進行細粒度控制類似于通過權限等級進行控制:創建對象實例時由當前用戶人工定義職能崗位的讀寫權限;訪問/操作對象實例時將實例的職能崗位配置與session[:duty_ids]進行比較,確定權限。具體實現方法不再贅述。
需要注意,職能崗位是不定項選擇,可以不選,也可以多選;在設計屬性結構和檢查算法時需要考慮這一點。
5 結論
該方案能夠實現粗粒度和細粒度相結合的權限控制,具有高自由度、高擴展性等特點;且能適應未來一定時間內組織機構變革的發展需求;可以滿足大多數業務信息系統權限控制的要求。
參考文獻:
[1] 張曉輝,王培康. 大型信息系統用戶權限管理[J].計算機應用,2000年11月,第20卷第11期:35頁
[2] 李海洋,楊麗娜. 科層職能式企業組織結構研究[J].合作經濟與科技,2012年10月號上,總第450期:50頁