ThinkPHP框架使用心得三 RBAC權限控制(1)使用


  最近有點小忙,好久沒有學習了。。。我懺悔。。。。

  RBAC英文全稱Role-Based Access Control。即基於角色的權限控制。它的權限控制原理是將個項目-模塊-操作的使用權限分配給角色組。然后將用戶分到各用戶組中,當然,一個用戶可能有多個用戶組。這樣用戶從屬於用戶組后就具有了該用戶組的相關操作權限。ThinkPHP中有一個封裝的很好的RBAC類庫,十分好用的說。同時官方也提供的demo包中也有rbac的例子,不過,據說好多人看着頭疼。我之前也拿這個例子來看,發現。。。超越了我的理解啊。。。。現在我對rbac的原理大體了解后來看它的demo,我知道問題所在了,它的demo寫的太好。對於我這種剛學習的人而言,絕大部分的精力會不由自主的放進他的操作流程,而會忽略最重要的數據表之間的操作,從而很可能難以理解rbac的原理。

  我自己寫了一個rbac的demo,最初的工作是利用curd編寫一個對文章的增改查的程序,連用戶登錄都免了,簡要代碼:

1 class IndexAction extends Action {
2     public function index() {}  //文章列表
3     public function add() {}  //新增文章
4     public function edit() {}  //文章編輯
5     public function view() {}  //文章查看
6 }

實現的效果:

一個簡單的系統搭建完成了,下面加入權限控制。

RBAC的實現至少需要五張數據表,(我使用tp默認的前綴think_)分別為:

thinkl_user 用戶表
字段 類型 說明
id int(11)  pk
username varchar(50)  
password varchar(50)  

 

thinkl_access 權限表
字段 類型 說明
role_id smallint(6)  角色id
node_id smallint(6)  節點id
level tinyint  表示所屬層次,項目=〉1,模塊=〉2,操作=〉3
module varchar(50)  

 

thinkl_node 節點表
字段 類型 說明
id smallint(6)  pk
name varchar(20)  
title varchar(50)  
status tinyint  
remark varchar(255)  
sort smallint(6)  
pid smallint(6)  
level tinyint  

 

thinkl_role角色表
字段 類型 說明
id smallint(6)  pk
name varchar(20)  
pid smallint(6)  
status tinyint  
remark varchar(255)  

 

thinkl_role_user 角色用戶關聯表
字段 類型 說明
role_id smallint(6)  
user_id smallint(6)  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 RBAC認證流程圖

rbac的原理其實就是這幾張表的數據邏輯關系。我是手動建立相關數據,一遍數據建立下來,邏輯理清了,基本原理也能理解的不差了。

(一)建立用戶表數據

建立三個用戶,分別為system,admin,user1

(二)建立角色組

建立兩個角色組,分別為admin,user,即管理組和普通組

(三)建立用戶和用戶組的關系

 將system,admin划歸角色組1

將user1划歸角色組2

這樣組合用戶的對應關系就建立好了

(4)建立節點表

所謂節點就是所有的項目、模塊、操作的列表。這張表應該算rbac的核心。

我的demo中項目名rabc,有一個模塊即IndexAction,下面還有index,add,edit,view四個操作。將這6條分別計入這張表中,注意pid的設置。同時level的值,1、2、3分別代表項目,模塊,操作。

(5)建立權限表

對於權限的分配就在access表中。

表中數據的意思是role_id=1的組,即admin組具有操作節點1,2,3,4,6的權限,不具備操作節點5即rbac-Index-edit的權限。role_id=2的組即用戶組織具有節點123的操作權限。

很重要的一點就是,權限的安排需要按層次來,即只有具備對項目的操作權限才能操作模塊,同理,只有具備對項目-模塊的操作權限才能操作下面的方法。

這樣,rbac的操作從數據表層面來講已經完成。下面對代碼進行修改以完成rbac的權限控制。

 首先,將RBAC.class.php復制到項目目錄Lib\Org下,也可以直接使用系統目錄Lib\ORG\Util下的類庫文件,只要能夠import即可。

然后,在項目配置文件中定義rbac的相關配置項:

//rbac配置項
    'USER_AUTH_ON'              =>true,
    'USER_AUTH_TYPE'        =>2,        // 默認認證類型 1 登錄認證 2 實時認證
    'USER_AUTH_KEY'             =>'authId',    // 用戶認證SESSION標記
    'ADMIN_AUTH_KEY'        =>'administrator',
    'USER_AUTH_MODEL'           =>'User',    // 默認驗證數據表模型
    'AUTH_PWD_ENCODER'          =>'md5',    // 用戶認證密碼加密方式
    'USER_AUTH_GATEWAY'         =>'/Public/login',// 默認認證網關
    'NOT_AUTH_MODULE'           =>'Public',    // 默認無需認證模塊
    'REQUIRE_AUTH_MODULE'       =>'',        // 默認需要認證模塊
    'NOT_AUTH_ACTION'           =>'',        // 默認無需認證操作
    'REQUIRE_AUTH_ACTION'       =>'',        // 默認需要認證操作
    'GUEST_AUTH_ON'             =>false,    // 是否開啟游客授權訪問
    'GUEST_AUTH_ID'             =>0,        // 游客的用戶ID
    'SHOW_RUN_TIME'             =>true,        // 運行時間顯示
    'SHOW_ADV_TIME'             =>true,        // 顯示詳細的運行時間
    'SHOW_DB_TIMES'             =>true,        // 顯示數據庫查詢和寫入次數
    'SHOW_CACHE_TIMES'          =>true,        // 顯示緩存操作次數
    'SHOW_USE_MEM'              =>true,        // 顯示內存開銷
    'DB_LIKE_FIELDS'            =>'title|remark',
    'RBAC_ROLE_TABLE'           =>'think_role',
    'RBAC_USER_TABLE'           =>'think_role_user',
    'RBAC_ACCESS_TABLE'         =>'think_access',
    'RBAC_NODE_TABLE'           =>'think_node',

這些配置項可以直接從tp的rbacdemo中復制。每項的意思也基本都注明了。不需要說太多了。

再然后定義一個PublicAction用來放置一些不需要進行認證的模塊。如果修改了配置項中NOT_AUTH_MODULE,那么就建立相應名稱的action。這里面放置登錄,登出,檢驗登錄情況等操作。如果用戶連登錄都發現沒有權限,這是個多么瘋狂的情況,用戶想登錄一直說:你丫無權操作,一邊涼快去。多抓狂。

代碼結構:

class PublicAction extends Action{

    // 用戶登錄頁面
    public function login() {
        if (!isset($_SESSION[C('USER_AUTH_KEY')])) {
            $this->display();
        } else {
            $this->redirect('Index/index');
        }
    }

    // 登錄檢測
    public function checkLogin() {
        
    }

    function loginout() {
        if (isset($_SESSION[C('USER_AUTH_KEY')])) {
            unset($_SESSION[C('USER_AUTH_KEY')]);
            unset($_SESSION);
            session_destroy();
            $this->assign("jumpUrl", __URL__ . '/login/');
            $this->success('登出成功!');
        } else {
            $this->error('已經登出!');
        }
    }

}

login,logout就是判斷session時候存在。存在就認為已經登錄,執行頁面跳轉或者刪掉這個session以達到退出效果。

checklogin()是rbac的具體實現

public function checkLogin() {
        if (empty($_POST['username'])) {
            $this->error('帳號錯誤!');
        } elseif (empty($_POST['password'])) {
            $this->error('密碼必須!');
        } 
        //生成認證條件
        $map = array();
        // 支持使用綁定帳號登錄
        $map['username'] = $_POST['username'];
        import('ORG.Util.RBAC');
        $authInfo = RBAC::authenticate($map);
        //使用用戶名、密碼和狀態的方式進行認證
        if (false === $authInfo) {
            $this->error('帳號不存在或已禁用!');
        } else {
            if ($authInfo['password'] != md5($_POST['password'])) {
                $this->error('密碼錯誤!');
            }
            $_SESSION[C('USER_AUTH_KEY')] = $authInfo['id'];
            if ($authInfo['username'] == 'system') {
                $_SESSION['administrator'] = true;
            }
            
            // 緩存訪問權限
            RBAC::saveAccessList();
            $this->success('登錄成功!');
        }
    }

首先判斷提交過來的表單信息,然后引入rbac類,然后調用RBAC::authenticate($map);來獲取認證信息。然后根據認證信息來判斷用戶時候登錄成功以及具有的權限。

再然后編寫一個BaseAction.class.php,這里放置一個自動方法,就是每次執行這個action時,這個方法會像構造函數一樣自動執行。這個方法就是檢查用戶權限。

function _initialize() {
        // 用戶權限檢查
        if (C ( 'USER_AUTH_ON' ) && !in_array(MODULE_NAME,explode(',',C('NOT_AUTH_MODULE')))) {
            import ( '@.Org.RBAC' );
            if (! RBAC::AccessDecision ()) {
                //檢查認證識別號
                if (! $_SESSION [C ( 'USER_AUTH_KEY' )]) {
                    //跳轉到認證網關
                    redirect ( PHP_FILE . C ( 'USER_AUTH_GATEWAY' ) );
                }
                // 沒有權限 拋出錯誤
                if (C ( 'RBAC_ERROR_PAGE' )) {
                    // 定義權限錯誤頁面
                    redirect ( C ( 'RBAC_ERROR_PAGE' ) );
                } else {
                    if (C ( 'GUEST_AUTH_ON' )) {
                        $this->assign ( 'jumpUrl', PHP_FILE . C ( 'USER_AUTH_GATEWAY' ) );
                    }
                    // 提示錯誤信息
                    $this->error ( L ( '_VALID_ACCESS_' ) );
                }
            }
        }
    }

然后修改IndexAction使它由Action改為繼承至BaseAction,這樣每個頁面的執行都會執行自動方法。以后如果增加新的模塊也讓它繼承BaseAction這樣就實現了權限控制了。

以上簡單的權限控制就完成了。代碼基本可以從官方例子中復制稍作修改即可。下面看看效果。

 結果不太好表示,按之前對表的編輯,結合實際調試,使用system登錄時,雖然他屬於admin組,而admin組並不具備編輯的權限,但是由於它是系統管理員,判定具有所有權限。用admin登錄可以發現只有編輯鏈接點擊時無權操作。使用user1登錄,除了能看首頁,其他什么事不能干。

就此,RBAC算是結束了。至於官方的demo,是可以再頁面上配置各種值,說白了就是將我的手動編輯表的過程在界面上實現。能夠理解原理,下面就可以試着做出官方demo那樣便捷的操作界面。

源代碼,希望大神指正。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM