附:添加注釋版RBAC類源碼


聲明:僅添加或修改了部分注釋。

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id: RBAC.class.php 2504 2011-12-28 07:35:29Z liu21st $

/**
 +------------------------------------------------------------------------------
 * 基於角色的數據庫方式驗證類
 +------------------------------------------------------------------------------
 * @category   ORG
 * @package  ORG
 * @subpackage  Util
 * @author    liu21st <liu21st@gmail.com>
 * @version   $Id: RBAC.class.php 2504 2011-12-28 07:35:29Z liu21st $
 +------------------------------------------------------------------------------
 */
// 配置文件增加設置
// ADMIN_AUTH_KEY 管理員認證SESSION標記
// USER_AUTH_KEY 用戶認證SESSION標記
// 
// $_SESSION[C('USER_AUTH_KEY')] 用來保存登陸成功后的用戶ID
// $_SESSION[C('ADMIN_AUTH_KEY')] 用來保存登陸成功后的管理員ID
// 
// USER_AUTH_ON 是否需要認證
// USER_AUTH_TYPE 認證類型,1是登陸認證,2是實時認證
// USER_AUTH_MODEL 用戶模型名稱
// GUEST_AUTH_ON 是否開啟游客授權訪問
// GUEST_AUTH_ID 游客的用戶ID
// 
// REQUIRE_AUTH_MODULE  需要認證模塊(若定義了,則只驗證給出的模塊;否則驗證所有模塊)
// NOT_AUTH_MODULE 無需認證模塊(若定義了“需要認證模塊”則本條定義無效)
// REQUIRE_AUTH_ACTION 需要認證操作(若定義了,則只驗證給出的操作;否則驗證所有操作)
// NOT_AUTH_ACTION 無需認證操作(若定義了“需要認證操作”則本條定義無效)
// 
// USER_AUTH_GATEWAY 認證網關,如果用戶沒有登錄則轉到這頁(URL路由規則)
// RBAC_DB_DSN  數據庫連接DSN
// RBAC_ROLE_TABLE 角色表名稱
// RBAC_USER_TABLE 用戶表名稱(應該是用戶、用戶組關系表)
// RBAC_ACCESS_TABLE 權限表名稱
// RBAC_NODE_TABLE 節點表名稱
//
/*
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `think_access` (
  `role_id` smallint(6) unsigned NOT NULL,
  `node_id` smallint(6) unsigned NOT NULL,
  `level` tinyint(1) NOT NULL,
  `module` varchar(50) DEFAULT NULL,
  KEY `groupId` (`role_id`),
  KEY `nodeId` (`node_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `think_node` (
  `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `title` varchar(50) DEFAULT NULL,
  `status` tinyint(1) DEFAULT '0',
  `remark` varchar(255) DEFAULT NULL,
  `sort` smallint(6) unsigned DEFAULT NULL,
  `pid` smallint(6) unsigned NOT NULL,
  `level` tinyint(1) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `level` (`level`),
  KEY `pid` (`pid`),
  KEY `status` (`status`),
  KEY `name` (`name`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `think_role` (
  `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `pid` smallint(6) DEFAULT NULL,
  `status` tinyint(1) unsigned DEFAULT NULL,
  `remark` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `pid` (`pid`),
  KEY `status` (`status`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 ;

CREATE TABLE IF NOT EXISTS `think_role_user` (
  `role_id` mediumint(9) unsigned DEFAULT NULL,
  `user_id` char(32) DEFAULT NULL,
  KEY `group_id` (`role_id`),
  KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
*/
class RBAC {
    // 認證方法
    
    // 得到需要鑒別的用戶列表
    // 即按照map中給的條件查詢用戶表(由USER_AUTH_MODEL給出)
    static public function authenticate($map,$model='')
    {
        if(empty($model)) $model =  C('USER_AUTH_MODEL');
        //使用給定的Map進行認證
        return M($model)->where($map)->find();
    }

    // 用於檢測用戶權限的方法,並保存到Session中
    // 將當前操作用戶擁有的所有權限保存到$_SESSION['_ACCESS_LIST']里
    // 開銷巨大,是對getAccessList的封裝
    static function saveAccessList($authId=null)
    {
        if(null===$authId)   $authId = $_SESSION[C('USER_AUTH_KEY')];
        // 如果使用普通權限模式,保存當前用戶的訪問權限列表
        // 對管理員開放所有權限        
        // 如果是實時認證(USER_AUTH_TYPE==2),則每次Decision的時候都刷新ACCESS_LIST,
        //    就不用在這刷新了
        if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] )
            $_SESSION['_ACCESS_LIST']    =    RBAC::getAccessList($authId);
        return ;
    }

    // 取得模塊的所屬記錄訪問權限列表 返回有權限的記錄ID數組
        // 返回當前模塊中當前用戶所擁有的權限列表
        // 開銷巨大,是對getModuleAccessList的封裝
    static function getRecordAccessList($authId=null,$module='') {
        if(null===$authId)   $authId = $_SESSION[C('USER_AUTH_KEY')];
        if(empty($module))  $module    =    MODULE_NAME;
        //獲取權限訪問列表
        $accessList = RBAC::getModuleAccessList($authId,$module);
        return $accessList;
    }

    //檢查當前操作是否需要認證,需要則返回true,不需要則返回false
    static function checkAccess()
    {
        //如果項目要求認證,並且當前模塊需要認證,則進行權限認證
        if( C('USER_AUTH_ON') ){
            $_module    =    array();
            $_action    =    array();
            if("" != C('REQUIRE_AUTH_MODULE')) {
                //需要認證的模塊
                $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE')));
            }else {
                //無需認證的模塊
                $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE')));
            }
            //檢查當前模塊是否需要認證
            if((!empty($_module['no']) && !in_array(strtoupper(MODULE_NAME),$_module['no'])) || 
                    (!empty($_module['yes']) && in_array(strtoupper(MODULE_NAME),$_module['yes']))) {
                        if("" != C('REQUIRE_AUTH_ACTION')) {
                            //需要認證的操作
                            $_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION')));
                        }else {
                            //無需認證的操作
                            $_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION')));
                        }
                        //檢查當前操作是否需要認證
                        if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || 
                            (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) {
                            return true;
                        }else {
                            return false;
                        }
            }else {
                return false;
            }
        }
        return false;
    }

    // 檢查用戶是否登錄
    // 如果沒有登錄,則嘗試進行“游客”登錄;如果無法以游客身份登錄,則跳轉到認證網關
    static public function checkLogin() {
        //檢查當前操作是否需要認證
        if(RBAC::checkAccess()) {
            //檢查認證識別號
            if(!$_SESSION[C('USER_AUTH_KEY')]) {
                if(C('GUEST_AUTH_ON')) {
                    // 開啟游客授權訪問
                    if(!isset($_SESSION['_ACCESS_LIST']))
                        // 保存游客權限
                        RBAC::saveAccessList(C('GUEST_AUTH_ID'));
                }else{
                    // 禁止游客訪問跳轉到認證網關
                    redirect(PHP_FILE.C('USER_AUTH_GATEWAY'));
                }
            }
        }
        return true;
    }

    // 權限認證的過濾器方法
    // 檢查當前操作是否被允許,返回bool值
    static public function AccessDecision($appName=APP_NAME)
    {
        //檢查是否需要認證
        if(RBAC::checkAccess()) {
            //存在認證識別號,則進行進一步的訪問決策
            $accessGuid   =   md5($appName.MODULE_NAME.ACTION_NAME);
            if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) {
                if(C('USER_AUTH_TYPE')==2) {
                    //實時認證模式,刷新ACCESS_LIST
                    //加強驗證和即時驗證模式 更加安全 后台權限修改可以即時生效
                    //通過數據庫進行訪問檢查
                    $accessList = RBAC::getAccessList($_SESSION[C('USER_AUTH_KEY')]);
                }else {
                    //登錄驗證模式,使用登錄后填充的ACCESS_LIST
                    // 如果是管理員或者當前操作已經認證過,無需再次認證
                    if( $_SESSION[$accessGuid]) {
                        return true;
                    }
                    $accessList = $_SESSION['_ACCESS_LIST'];
                }
                //判斷是否為組件化模式,如果是,驗證其全模塊名
                $module = defined('P_MODULE_NAME')?  P_MODULE_NAME   :   MODULE_NAME;
                if(!isset($accessList[strtoupper($appName)][strtoupper($module)][strtoupper(ACTION_NAME)])) {
                    //沒有權限
                    $_SESSION[$accessGuid] = false;
                    return false;
                }
                else {
                    $_SESSION[$accessGuid] = true;
                }
            }else{
                //管理員無需認證
                return true;
            }
        }
        return true;
    }

    /**
     +----------------------------------------------------------
     * 取得當前認證號的所有權限列表
     * (得到指定用戶擁有的所有操作權限)
     +----------------------------------------------------------
     * @param integer $authId 用戶ID
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     */
    static public function getAccessList($authId)
    {
        // Db方式權限數據
        $db     =   Db::getInstance(C('RBAC_DB_DSN'));
        $table = array('role'=>C('RBAC_ROLE_TABLE'),
            'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE'));
        // 首先檢查該用戶所在用戶組擁有權限的所有項目
        $sql    =   "select node.id,node.name from ".
                    $table['role']." as role,".
                    $table['user']." as user,".
                    $table['access']." as access ,".
                    $table['node']." as node ".
                    "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id  or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=1 and node.status=1";
        $apps =   $db->query($sql);
        $access =  array();
        foreach($apps as $key=>$app) {
            $appId    =    $app['id'];
            $appName     =     $app['name'];
            // 讀取項目的模塊權限
            $access[strtoupper($appName)]   =  array();
            // 再檢查每個有權限的項目下面所有有權限的模塊
            $sql    =   "select node.id,node.name from ".
                    $table['role']." as role,".
                    $table['user']." as user,".
                    $table['access']." as access ,".
                    $table['node']." as node ".

                    "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id  or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=2 and node.pid={$appId} and node.status=1";
            $modules =   $db->query($sql);
            // 判斷是否存在公共模塊的權限
            $publicAction  = array();
            foreach($modules as $key=>$module) {
                $moduleId     =     $module['id'];
                $moduleName = $module['name'];
                if('PUBLIC'== strtoupper($moduleName)) {                
                $sql    =   "select node.id,node.name from ".
                    $table['role']." as role,".
                    $table['user']." as user,".
                    $table['access']." as access ,".
                    $table['node']." as node ".
                    "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id  or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1";
                    $rs =   $db->query($sql);
                    foreach ($rs as $a){
                        $publicAction[$a['name']]     =     $a['id'];
                    }
                    unset($modules[$key]);
                    break;
                }
            }
            // 再檢查每個有權限的模塊(除公共模塊)下面所有有權限的操作,依次讀取模塊的操作權限
            foreach($modules as $key=>$module) {
                $moduleId     =     $module['id'];
                $moduleName = $module['name'];
                $sql    =   "select node.id,node.name from ".
                    $table['role']." as role,".
                    $table['user']." as user,".
                    $table['access']." as access ,".
                    $table['node']." as node ".
                    "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id  or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1";
                $rs =   $db->query($sql);
                $action = array();
                foreach ($rs as $a){
                    $action[$a['name']]     =     $a['id'];
                }
                // 和公共模塊的操作權限合並
                $action += $publicAction;
                $access[strtoupper($appName)][strtoupper($moduleName)]   =  array_change_key_case($action,CASE_UPPER);
            }
        }
        return $access;
    }

    /**
     +----------------------------------------------------------
     * 讀取指定模塊、指定用戶擁有的所有權限列表
     +----------------------------------------------------------
     * @param integer $authId 用戶ID
     * @param string $module 模塊名
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     */// 讀取指定模塊、指定用戶擁有的所有權限列表
    static public function getModuleAccessList($authId,$module) {
        // Db方式
        $db     =   Db::getInstance(C('RBAC_DB_DSN'));
        $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'));
        $sql    =   "select access.node_id from ".
                    $table['role']." as role,".
                    $table['user']." as user,".
                    $table['access']." as access ".
                    "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id  or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and  access.module='{$module}' and access.status=1";
        $rs =   $db->query($sql);
        $access    =    array();
        foreach ($rs as $node){
            $access[]    =    $node['node_id'];
        }
        return $access;
    }
}

 


免責聲明!

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



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