首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Yii srbac 權限擴展模塊深度解析:工作原理、數據表結構與核心驗證流程

     編輯:PHP 相關知識

前言:為什麼選擇 srbac?

Yii 1.x 內置 CAuthManager (CDbAuthManager) 提供 RBAC 基礎,但缺乏圖形化管理界面、自動路由映射、多級繼承可視化。srbac 是社區最成熟的 RBAC 管理模塊,提供 Web 界面管理角色/任務/操作、自動掃描控制器動作生成操作項、支持業務規則。本文深度解析其數據表設計、核心驗證邏輯、控制器集成方式,幫助開發者理解底層原理並進行二次開發。

一、核心數據表結構

srbac 通過配置映射三張核心表(可自定義表名):

邏輯表默認表名關鍵字段說明
授權項目表AuthItemname(PK), type(0操作/1任務/2角色), description, bizrule, data存儲所有角色、任務、操作節點
項目關係表AuthItemChildparent, child (雙PK)父子繼承關係:角色→任務、任務→操作,支持多級
分配表AuthAssignmentitemname, userid (雙PK), bizrule, data用戶-角色綁定,bizrule 支持動態判斷

配置示例 (main.php / module config)

'modules' => array(
    'srbac' => array(
        'itemTable' => 'AuthItem',
        'itemChildTable' => 'AuthItemChild',
        'assignmentTable' => 'AuthAssignment',
        'userClass' => 'User',
        'userIdColumn' => 'id',
        'userNameColumn' => 'username',
        'layout' => 'application.views.layouts.main',
        'debug' => false, // 生產環境必須 false
    ),
),

二、控制器集成:SBaseController 基類模式

所有需權限控制的控制器繼承 SBaseController(而非 Controller):

class SBaseController extends Controller {
    protected function beforeAction($action) {
        // 1. 構建訪問標識:模塊.控制器.動作 (首字母大寫)
        $del = Yii::app()->getModule('srbac')->delimiter; // 默認 '.'
        $mod = $this->module ? $this->module->id . $del : '';
        $controller = implode('.', array_map('ucfirst', explode('/', $this->id)));
        $access = $mod . $controller . ucfirst($this->action->id); // 如: admin.UserController.View

        // 2. 白名單檢查
        if (in_array($access, $this->allowedAccess())) return true;

        // 3. srbac 未安裝/調試模式放行
        $srbac = Yii::app()->getModule('srbac');
        if (!$srbac->isInstalled() || $srbac->debug) return true;

        // 4. 核心權限驗證
        if (!Yii::app()->user->checkAccess($access) || Yii::app()->user->isGuest) {
            $this->onUnauthorizedAccess(); // 默認導向登錄/403
            return false;
        }
        return true;
    }

    // 可覆寫:白名單(如登錄、錯誤、公共頁)
    public function allowedAccess() {
        return array(
            'SiteController.Login', 'SiteController.Logout', 'SiteController.Error',
            'SiteController.Captcha', 'SrbacController.*', // srbac 管理界面放行
        );
    }

    // 可覆寫:無權限處理
    protected function onUnauthorizedAccess() {
        if (Yii::app()->request->isAjaxRequest) {
            echo CJSON::encode(array('success' => false, 'msg' => '權限不足'));
            Yii::app()->end();
        } else {
            $this->redirect(Yii::app()->user->loginUrl);
        }
    }
}

三、核心驗證流程深度追蹤

Yii::app()->user->checkAccess($access) 最終調用 CDbAuthManager::checkAccess(),流程如下:

1. 獲取用戶角色分配

// CDbAuthManager::getAuthAssignments($userId)
$rows = $this->db->createCommand()
    ->select()->from($this->assignmentTable)
    ->where('userid=:userid', array(':userid'=>$userId))
    ->queryAll();
foreach ($rows as $row) {
    $assignments[$row['itemname']] = new CAuthAssignment($this, $row['itemname'], $row['userid'], $row['bizrule'], @unserialize($row['data']));
}

2. 遞歸檢查權限 (checkAccessRecursive)

protected function checkAccessRecursive($itemName, $userId, $params, $assignments) {
    // 1. 獲取授權項目定義
    if (($item = $this->getAuthItem($itemName)) === null) return false;

    // 2. 執行項目級 bizrule
    if (!$this->executeBizRule($item->bizRule, $params, $item->data)) return false;

    // 3. 默認角色直接通過
    if (in_array($itemName, $this->defaultRoles)) return true;

    // 4. 直接分配檢查
    if (isset($assignments[$itemName])) {
        $assignment = $assignments[$itemName];
        if ($this->executeBizRule($assignment->bizRule, $params, $assignment->data)) return true;
    }

    // 5. 遞歸查找父角色(關鍵:支持多級繼承)
    $parents = $this->db->createCommand()
        ->select('parent')->from($this->itemChildTable)
        ->where('child=:name', array(':name'=>$itemName))
        ->queryColumn();
    foreach ($parents as $parent) {
        if ($this->checkAccessRecursive($parent, $userId, $params, $assignments)) return true;
    }
    return false;
}

3. 業務規則執行

public function executeBizRule($bizRule, $params, $data) {
    return $bizRule === '' || $bizRule === null || ($this->showErrors ? eval($bizRule) != 0 : @eval($bizRule) != 0);
}
// 典型 bizrule 示例:return Yii::app()->user->id == $params['post']->author_id; // 僅作者可編輯

四、關鍵設計亮點與擴展點

特性實現方式擴展建議
自動掃描控制器動作SrbacModule::install() 遍歷 controllers 目錄,解析 action* 方法生成 AuthItem (type=0)可擴展掃描註解 @permission 自定義分組/描述
多級角色繼承AuthItemChild 父子關係 + 遞歸查找父節點注意避免循環繼承,安裝時檢測
動態權限 (bizrule)PHP 代碼字符串存儲,運行時 eval() 執行安全風險大,建議改用 PHP 7.4+ 箭頭函數序列化或策略類替代
Ajax/RESTful 支持onUnauthorizedAccess() 區分請求類型返回 JSON/重定向統一 API 錯誤碼 403 + 結構化響應
管理界面SrbacController 提供角色/任務/操作 CRUD、矩陣分配、圖形化繼承圖可二次開發添加權限變更審計日志

五、常見問題與避坑

  • 安裝後無法訪問:檢查 debug=false、allowedAccess() 包含 SrbacController.*、用戶有 srbac 角色。
  • 動作名稱大小寫不匹配:srbac 生成操作名為 ActionIndex (首字母大寫),驗證時 ucfirst($action->id) 必須一致。
  • 模塊分隔符配置:delimiter 默認 .,若控制器 ID 含 / (如 admin/user),生成 admin.UserController.Action,需與 AuthItem 名稱完全一致。
  • bizrule eval 性能與安全:高併發下 eval 開銷大,且有代碼注入風險。建議:
    1. 簡單規則用 bizrule 字符串表達式(如 return $params['userId']==$data['ownerId'];)
    2. 複雜規則遷移至 AuthManager::checkAccess 覆寫或策略類,棄用 eval。
  • 超管繞過權限:在 allowedAccess() 或 checkAccessRecursive 入口判斷 Yii::app()->user->isSuperAdmin 直接返回 true。

結語

srbac 通過三表 RBAC 模型 + 控制器基類攔截 + 遞歸權限解析 + Web 管理界面,為 Yii 1.x 提供了開箱即用的完整權限管理解決方案。理解其數據表關係、checkAccess 遞歸邏輯、bizrule 執行機制、控制器集成點,能讓你在權限異常排查、性能優化、功能擴展(如多租戶、動態權限、API Token 鑑權)時得心應手。建議新項目考慮遷移至 Yii 2.x yii2-rbac 或 mdmsoft/yii2-admin,享受更現代的架構與類型安全。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved