這幾天因為要做一個項目,需要可以對Web應用中通用功能進行封裝,其中一個很重要的涉及到了對用戶、角色和權限部分的靈活管理。所以基於TP框架自己封裝了一個對操作權限和菜單權限進行靈活配置的可控制模式。
RBAC角色權限分配模式大家或許都不陌生,其重要的訪問控制原理就是將權限基於角色進行動態分配,在一個工作模式中,每個人都被分配了不同的角色,因為每個人角色的不同所以每個人負責的事情也不同。最簡單的舉一個例子來說吧,就一個大學而言,一個大學分為校長、某個學院的院長、某個系的系主任,他們每個人都有不同的角色,校長要做可能就是宏觀把控整個學校的大方向,院長就是對自己這個學院負責,系主任呢就是應該對自己系里面的各種具體的事情進行處理和監督。從例子中,大家可能也已經看出來了,在整個的工作組織中,由上而下分為了很多不同的角色,而且每個不同角色的人承擔的責任也不同,所以我們在我們的靈活可配置的控制模式中應該做到對不同級別、不同角色的用戶的操作權限進行動態配置,這樣就不用我們寫大量的重復代碼,節省了我們大量的時間。
其實,在TP框架中也自帶了一個角色權限分配的封裝代碼,可是我自己不太想用它的,所以自己去封裝吧。
在RBAC的權限分配模式中,我們所有的權限都是基於角色,所以我們應該有一個非常重要的可以左右聯系的表->role表(角色表)。現在我們有了角色表,可是我們最終的服務對象還是我們的用戶,真正使角色有意義的是用戶,因為是某個用戶具有某個角色,所以我們還應該有一個基本的用戶表->user表(用戶表)。現在角色左邊的用戶表有了,那么還缺少一個什么呢?那就是我們的權限表,因為我們不同的操作對應的是是否具有該操作的執行權限,所以我們還應該有一個基本的權限表->access表(權限表)。現在有了這些表,我們還應該將這些表聯系起來,那就是用戶角色表->user_role表和角色權限表->role_access表。上面這五個表就是RBAC模式中最基本的5張表。但是現在我還想能夠將菜單也做成靈活可定制的,所以還需要有一個menu表。其實到了這里,就是出現一個分歧,那就是我們菜單和角色的關聯,現在有兩個途徑,一個就是將菜單也當成用戶的操作權限,將菜單作為一個權限放在權限表中去為角色分配。另外一個就是在擴展一個角色菜單表role_menu表,我們將菜單級別的權限配置專門進行管理,做菜單的靈活配置。
所有的表有了,接下來就是做到如何才能對操作權限和菜單權限進行控制呢?這就需要針對不同的底層框架去實現了,在TP框架中,自己一開始想說去用行為類實現。我想專門去實現了一個檢查權限的行為類,在每次執行操作的時候都去檢查是否有該操作權限,若沒有則給出提示,並停止執行代碼。雖然整體的設計沒有錯,可是自己在實現時,發現我們每次都要去用B方法調用該行為類,讓它去執行run()方法,這樣顯然不方便。后來自己好好想了想,發現剛才自己的想法太蠢了,其實自己完全沒有必要去用行為類做,僅僅是一個控制器就完全可以實現。
具體的做法是這樣,我封裝了一個基類的AdminController(因為主要是針對后台的),讓所有后台應用的控制器都去繼承自AdminController,在每個控制器的構造函數中都去繼承AdminController的構造函數,這樣我每次的請求在執行時都會去初始化AdminController中的構造函數,然后我在基類的構造函數中去截獲當前執行操作的控制器和對應的方法,然后去對比操作權限,如果存在則“放行”,如果沒有,那就不好意思,給出一個提示哈。
菜單也是相似的操作。不過我在控制器中設置了對admin管理員的自動過濾,讓admin自動擁有所有的菜單和權限。
經過以上的操作,我們就實現了對權限的控制,並且是對菜單級別和按鈕級別均有控制。
好了,接下來奉上在權限判斷部分的代碼,供大家參考。
1 public function __construct(){ 2 parent::__construct(); 3 if(session("?loginuser")){ //表示當前人已經登錄,則我們應該獲取 4 $loginuser=session("loginuser"); //獲取當前登錄人的session值 5 if($loginuser!="admin"){ //只有在當前登錄人不是admin的時候,我們才需要去獲取當前人執行的請求方法,然后進行權限對比 6 $con_name=CONTROLLER_NAME; 7 $fun_name=ACTION_NAME; 8 $url=$con_name."/".$fun_name; 9 $access_urls=session("access_urls"); //將所有目前session中的權限獲取出來 10 11 //echo "<script>alert('".$url."')</script>"; 12 if($fun_name!="ajaxIndex"){ 13 14 //echo "<script>alert('".$url."')</script>"; 15 if($url=="Index/index"||$url=="Index/head"||$url=="Index/left"||$url=="Index/right"){ //我們默認給出顯示首頁的三個方法的權限 16 17 } 18 else{ 19 $is_have="error"; 20 foreach ($access_urls as $key => $value) { 21 # code... 22 if(in_array($url, $value)){ 23 $is_have="ok"; 24 break; 25 } 26 } 27 28 if($is_have=="error"){ //若最終為error,則表示當前沒有該權限 29 echo "<script>alert('您不具備該權限!')</script>"; 30 die(); 31 } 32 } 33 } 34 } 35 36 } 37 else{ 38 $this->redirect("Login/showLogin"); 39 }
好了,上述部分就是一個簡單的權限控制模式,並且是到按鈕級別喲。
在補充一句吧,上述只是基於TP框架的封裝。其它具體框架可以具體操作,比如Laravel框架,在Laravel中新推出了一個叫中間件的東西,在這個中間件中所有的操作都會經過這個中間件,所以,我們就可以在這個中間件中做非常多的事情啦。
好了,到此結束,也寫上那句話吧:此文屬於博主原創,如果轉載,請標明出處喲。
