單一 CWebUser 實例導致前後台共用 Session,登錄/退出相互影響。解決思路:為後台模塊註冊獨立的 CWebUser 子類實例(如 AdminWebUser),並設置不同的 stateKeyPrefix。
'components'=>[
'user'=>[
'class'=>'WebUser', // 繼承 CWebUser
'stateKeyPrefix'=>'member', // 前台 session 前綴
'allowAutoLogin'=>true,
],
],
class AdminModule extends CWebModule {
public function init() {
parent::init();
$this->setImport(['admin.models.*', 'admin.components.*']);
Yii::app()->setComponents([
'errorHandler'=>['class'=>'CErrorHandler', 'errorAction'=>'admin/default/error'],
'admin'=>[ // 後台專用 user 組件
'class'=>'AdminWebUser',
'stateKeyPrefix'=>'admin', // 後台 session 前綴
'loginUrl'=>Yii::app()->createUrl('admin/default/login'),
],
], false); // false = 不覆蓋已有組件
}
public function beforeControllerAction($controller, $action) {
if (parent::beforeControllerAction($controller, $action)) {
$route = $controller->id.'/'.$action->id;
$public = ['default/login', 'default/error'];
if (Yii::app()->admin->isGuest && !in_array($route, $public))
Yii::app()->admin->loginRequired();
return true;
}
return false;
}
}
// 前台 WebUser
class WebUser extends CWebUser {
public function __get($name) {
if ($this->hasState('__userInfo')) {
$u = $this->getState('__userInfo', []);
if (isset($u[$name])) return $u[$name];
}
return parent::__get($name);
}
public function login($identity, $duration) {
$this->setState('__userInfo', $identity->getUser());
parent::login($identity, $duration);
}
}
// 後台 AdminWebUser(結構同前台,鍵名改為 __adminInfo)
class AdminWebUser extends CWebUser {
public function __get($name) {
if ($this->hasState('__adminInfo')) {
$u = $this->getState('__adminInfo', []);
if (isset($u[$name])) return $u[$name];
}
return parent::__get($name);
}
public function login($identity, $duration) {
$this->setState('__adminInfo', $identity->getUser());
parent::login($identity, $duration);
}
}
// 前台退出
Yii::app()->user->logout(false); // false = 不銷毀整個 session
// 後台退出
Yii::app()->admin->logout(false);
CWebUser::logout(false) 內部調用 clearStates(),僅刪除 $_SESSION 中以當前 stateKeyPrefix 開頭的鍵,實現精準隔離。
前台驗證 User 表,後台驗證 Staff 表,各自實現 authenticate()、getUser()、getId(),登錄時傳入對應 CWebUser 實例即可。
Yii::app()->userYii::app()->admin此方案在單入口、單應用下實現了真正的前後台會話隔離,避免雙入口維護成本。