yii IUserIdentity驗證類的使用

驗證和授權在頁面需要限制訪問時用到。驗證就是確認某人就是他所聲稱的那個人。通常涉及到用戶名和密碼,但也包含其他方式,例如智能卡,指紋等。授權是在驗證用戶後,查明他是否被允許管理指定的資源。通常判斷他是否是有權訪問資源的角色的成員。

Yii 有一個內置的驗證/授權框架,它易於使用且可定製。

Yii 認證框架的核心是預聲明的用戶組件,它是一個實現 IWebUser 接口的對象。用戶組件代表了當前用戶的持久身份信息。可以使用 Yii::app()->user 來訪問。

使用用戶組件,可以使用 CWebUser::isGuest 檢查一個用戶是否已經登錄;我們可以登錄或者註銷一個用戶; 調用 CWebUser::checkAccess 可以檢查用戶是否可以執行特定的操作; 也可以得到用戶的唯一身份和另外的持久身份信息。

定義身份類

如之前所說, 驗證是確認用戶的身份。典型的網絡應用驗證通常是使用用戶名和密碼的組合來確認用戶的身份。然而,也可以包含其他的方法。爲了掩飾兼容各種驗證方法, Yii 認證框架引入了身份類。

我們定義一個身份類,它含有實際的驗證邏輯。身份類應當實現 IUserIdentity 接口。不同的身份類可以實現不同的驗證方法 (例如 OpenID, LDAP, Twitter OAuth, Facebook Connect). 推薦擴展 CUserIdentity 編寫你自己的類,CUserIdentity 是使用用戶名和密碼這種驗證方法的基類。

定義身份類最主要的工作是實現 [IUserIdentity::authenticate] 方法. 這個方法封裝了驗證的邏輯細節。在身份類中也可以聲明額外的身份信息。

例子
在下面的例子中,我們使用一個身份類來演示使用數據庫方法來驗證。這是非常典型的方法。用戶需要輸入用戶名和密碼到登錄表單中,然後我們驗證這些賬號信息,使用 ActiveRecord ,向數據庫中的表來查詢。我們需要演示的是

  • 實現 authenticate() 方法來根據數據庫驗證賬號信息.

  • 重寫 CUserIdentity::getId() 方法來返回 _id 屬性,因爲默認返回用戶名作爲 ID.

  • 使用 setState() (CBaseUserIdentity::setState) 方法來演示儲存其他信息,這些信息可以在隨後的訪問被輕鬆獲取

<?php
class UserIdentity extends CUserIdentity
{
    private 
$_id;
    public function 
authenticate()
    {
        
$record=User::model()->findByAttributes(array('username'=>$this->username));
        if(
$record===null)
            
$this->errorCode=self::ERROR_USERNAME_INVALID;
        else if(
$record->password!==md5($this->password))
            
$this->errorCode=self::ERROR_PASSWORD_INVALID;
        else
        {
            
$this->_id=$record->id;
            
$this->setState('title'$record->title);
            
$this->errorCode=self::ERROR_NONE;
        }
        return !
$this->errorCode;
    }

    public function 
getId()
    {
        return 
$this->_id;
    }
}
?>

下個小結的登錄和註銷中,我們將看到把這個身份類放在用戶的登錄方法中。任何儲存在狀態中的信息 (使用 CBaseUserIdentity::setState) 將被傳遞給 CWebUser, 它們被保存到持久存儲中,例如 session. 這些信息可以作爲 CWebUser 的屬性被訪問。在我們的例子彙總,使用 $this->setState('title',$record->title) 存儲用戶 title 信息. 在登錄完成之後,可以使用 Yii::app()->user->title 得到當前用戶的 title 信息。

信息: CWebUser 默認使用 session 作爲用戶身份信息的持久存儲方式。若啓用了基於 cookie 的登錄 (通過設置 CWebUser::allowAutoLogin 爲 true), 用戶身份也可以被保存在 cookie 中。一定不要聲明敏感信息 (例如密碼) 爲 persistent.

登錄和註銷

現在已經看到了創建一個用戶身份的例子,我們使用它來簡化登錄和註銷動作。如下代碼展示了它們如何被實現的:

<?php
// Login a user with the provided username and password.
$identity=new UserIdentity($username,$password);
if(
$identity->authenticate())
    
Yii::app()->user->login($identity);
else
    echo 
$identity->errorMessage;
......
// Logout the current user
Yii::app()->user->logout();
?>

這裏我們創建了一個 UserIdentity 對象並傳遞賬號信息 (也就是用戶提交的 $username 和 $password ) 到它的構造器中. 然後我們只需調用 authenticate() 方法. 若成功,傳遞身份信息到 CWebUser::login 方法,在此方法中身份信息被存儲到持久存儲 (默認是 PHP session ) . 若驗證失敗, 我們可以查詢 errorMessage 屬性來了解爲何失敗.

判斷一個用戶是否登錄非常簡單,使用 Yii::app()->user->isGuest 即可. 若使用持久存儲如 session (默認地) 和/或 cookie (下面討論) 來存儲身份信息, 用戶在隨後的請求中保持已登錄狀態. 這樣,我們無需爲每次請求使用 UserIdentity 類和完整的登錄驗證. CWebUser 將自動從持久存儲中載入身份信息,用它們來檢測Yii::app()->user->isGuest 返回的是 true 還是 false.

基於 cookie 的登錄

默認情況下, 用戶在一段閒置期限後將被註銷, 取決於 session 配額. 爲了改變這個行爲, 我們可以設置 user 組件的 allowAutoLogin 屬性爲 true 並傳遞 duration 參數到 CWebUser::login 方法中. 在指定的期限內用戶仍然處於登錄狀態,即使他關閉了瀏覽器窗口 注意此特徵需要用戶的瀏覽器接受 cookie.

<?php
// Keep the user logged in for 7 days.
// Make sure allowAutoLogin is set true for the user component.
Yii::app()->user->login($identity,3600*24*7);
?>

如之前所述,當啓用了基於 cookie 的登錄, 通過 CBaseUserIdentity::setState 存儲的狀態將也保存在 cookie 中. 下次用戶登錄時, 這些狀態從 cookie 中讀取,並且可以使用 Yii::app()->user 來訪問。

雖然 Yii 有方法來防止狀態 cookie 在客戶端被篡改, 我們強烈建議安全敏感信息不要儲存爲狀態. 而是選擇存儲在服務器端,從服務器端的持久存儲中讀取 (例如數據庫).

此外, 位於要求較高的網絡應用,我們建議使用如下策略來增強基於 cookie 登錄的安全性:

  • 當用戶填寫登錄表單後成功登錄, 在 cookie 狀態和服務器端的持久存儲(如數據庫)中生成並存儲一個隨機 key .

  • 在隨後的訪問中, 當通過 cookie 信息實現驗證後, 我們對比這兩個隨機 key 來確保登錄前他們是一致的。

  • 若用戶通過表單再次登錄, key 需要重新生成.

通過使用上面的策略, 我們消除了這種可能性:一個用戶可以重新使用舊的包含過期 state 信息的 state cookie。

爲了實現上面的策略, 我們需要重寫如下兩個方法:

  • CUserIdentity::authenticate(): 這裏是認證真正執行的地方. 若用戶被認證, 我們應當重新生成一個新的隨機 key, 並把它存儲到數據庫以及身份狀態中( 通過CBaseUserIdentity::setState).

  • CWebUser::beforeLogin(): 它在用戶登錄時被調用. 我們應當檢查 state cookie 中的 key 是否和數據庫中的是相同的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章