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

Yii 框架權限控制進階:基於角色的存取控制濾鏿實作(非 RBAC)

     編輯:PHP 綜合知識

前言

Yii 1.x 提供兩套授權機制:簡單的 CAccessControlFilter(ACF)與完整的 RBAC。對於中小型專案,ACF 配合資料庫角色欄位即可滿足分級存取需求,無需引入複雜 RBAC。本文詳細說明如何擴充 `CWebUser`、修改設定、改寫 `accessRules()` 實現「管理員/一般用戶」兩級權限控制。

一、預設 ACF 行為回顧

Gii 生成的 Controller 預設包含:

public function filters() {
    return [
        'accessControl', // 啟用 ACF
        'postOnly + delete',
    ];
}

public function accessRules() {
    return [
        ['allow', 'actions' => ['index','view'], 'users' => ['*']],
        ['allow', 'actions' => ['create','update'], 'users' => ['@']],
        ['allow', 'actions' => ['admin','delete'], 'users' => ['admin']], // 硬編碼用戶名
        ['deny', 'users' => ['*']],
    ];
}
缺點:`users => ['admin']` 硬編碼用戶名,無法動態對應資料庫角色。

二、三步驟實現角色基礎存取控制

步驟 1:建立 WebUser 元件擴充

檔案:`protected/components/WebUser.php`

<?php
class WebUser extends CWebUser {
    private $_model = null;

    // 取得 first_name(示例)
    public function getFirstName() {
        $user = $this->loadUser(Yii::app()->user->id);
        return $user ? $user->first_name : '';
    }

    // 核心:判斷是否為管理員
    public function isAdmin(): bool {
        $user = $this->loadUser(Yii::app()->user->id);
        return $user !== null && $user->role === '管理員'; // 對應資料庫 role 欄位
    }

    protected function loadUser($id = null) {
        if ($this->_model === null && $id !== null) {
            $this->_model = User::model()->findByPk($id);
        }
        return $this->_model;
    }
}

步驟 2:修改應用設定啟用自定義 User 元件

檔案:`protected/config/main.php`

'components' => [
    'user' => [
        'allowAutoLogin' => true,
        'class' => 'WebUser', // 關鍵:指定自定義類別
    ],
    // ...
],

步驟 3:改寫 accessRules() 使用 expression 判斷

public function accessRules() {
    return [
        ['allow', 'actions' => ['index','view'], 'users' => ['*']],
        ['allow', 'actions' => ['create','update'], 'users' => ['@']],
        // 使用 expression 動態評估 PHP 運算式
        ['allow', 'actions' => ['admin','delete'], 'expression' => 'Yii::app()->user->isAdmin()'],
        ['deny', 'users' => ['*']],
    ];
}
關鍵點: `expression` 允許任意 PHP 運算式,回傳 `true` 即通過。此處呼叫 `Yii::app()->user->isAdmin()`,自動委派給擴充的 `WebUser::isAdmin()`。

三、進階:多角色支援與通用檢查方法

1. WebUser 增加通用角色檢查

public function hasRole(string $role): bool {
    $user = $this->loadUser(Yii::app()->user->id);
    return $user !== null && $user->role === $role;
}

public function hasAnyRole(array $roles): bool {
    $user = $this->loadUser(Yii::app()->user->id);
    return $user !== null && in_array($user->role, $roles, true);
}

2. accessRules() 多角色範例

public function accessRules() {
    return [
        ['allow', 'actions' => ['index','view'], 'users' => ['*']],
        ['allow', 'actions' => ['create','update'], 'users' => ['@']],
        // 僅管理員與編輯可存取 admin/delete
        ['allow', 'actions' => ['admin','delete'], 'expression' => 'Yii::app()->user->hasAnyRole(["管理員","編輯"])'],
        ['deny', 'users' => ['*']],
    ];
}

四、效能優化:快取用戶模型

`WebUser::loadUser()` 已使用實例變數 `$_model` 快取,同一請求內多次呼叫 `isAdmin()`/`hasRole()` 只查詢一次資料庫。若需跨請求快取,可整合 `CCache`:

protected function loadUser($id = null) {
    if ($this->_model === null && $id !== null) {
        $cacheKey = "user_{$id}";
        if (($this->_model = Yii::app()->cache->get($cacheKey)) === false) {
            $this->_model = User::model()->findByPk($id);
            if ($this->_model) Yii::app()->cache->set($cacheKey, $this->_model, 300); // 5分鐘
        }
    }
    return $this->_model;
}

五、常見問題與避坑指南

問題原因解決
expression 不生效拼寫錯誤 / 未返回布林值確認運算式回傳 true/false,使用 `var_dump` 除錯
角色變更未即時生效WebUser 快取舊模型 / Session 未更新登出重登、或實作 `afterSave` 清除快取
超級管理員無法存取資料庫 role 值不匹配(如 'admin' vs '管理員')統一角色常數定義,避免魔術字串
API 無狀態請求無法使用ACF 依賴 Session/CookieAPI 改用 Token 驗證 + 自定義 Filter

六、從 ACF 遷移至 RBAC 的判斷標準

  • 角色超過 3-4 種,權限矩陣複雜(如「編輯可刪除自己的文章,不可刪除他人」)。
  • 需支援操作層級權限(如「修改價格」vs「修改描述」)。
  • 權限頻繁變動,需後台視覺化管理。
  • 多應用/微服務共享權限體系。
未達上述條件,ACF + `expression` 彈性足夠,維護成本遠低於 RBAC。

七、總結

Yii `CAccessControlFilter` 配合 `CWebUser` 擴充與 `expression` 運算式,能以極低複雜度實現基於資料庫角色的分級存取控制。核心在於:將授權邏輯從 Controller 遷移至 User 元件,Controller 僅宣告規則,業務判斷集中在 `WebUser`。此模式符合單一職責原則,且平滑過渡至未來 RBAC 遷移(只需替換 `isAdmin()` 實作)。

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