This article describes a new method for handling front and back logins in Yii. Share it with everyone for your reference, the details are as follows:
Because I am currently working on a project that involves front and backend login issues, I handle the backend as a module. I see many people put two entry files index.php and admin.php, and then point to the frontend and backend respectively. Although this method is very good, it can completely separate the front and backend, but I always feel that this method is a bit far-fetched. What is the difference between this and the two applications? It is better to make two apps using one framework. And the official Yii background usage method is also to use Module. But Moudle's method has a very troublesome problem, that is, when using Cwebuser to log in, there will be a problem of logging in and logging out at the same time in the front and backend, which is obviously unreasonable. It took me a long time to find the method that will be introduced below. Of course, many of them were based on other people's methods and I made slight changes. My initial approach was to set up an isadmin session when logging in to the backend, and then log out of the session when logging in to the frontend. This could only tell whether it was a frontend login or a background login, but it couldn't log in both the frontend and the backend at the same time, that is, frontend login. Log out after logging into the background, and log out after logging into the front desk. The root cause of this problem is that we use the same Cwebuser instance and cannot set up front and backend sessions at the same time. To solve this problem, we must use different Cwebuser instances to log in to the front and backend. The following is my approach. First, look at the configuration of the front-end user (Cwebuser) in protected->config->main.php:
'user'=>array( 'class'=>'WebUser',//这个WebUser是继承CwebUser,稍后给出它的代码 'stateKeyPrefix'=>'member',//这个是设置前台session的前缀 'allowAutoLogin'=>true,//这里设置允许cookie保存登录信息,一边下次自动登录 ),
When you use Gii to generate an admin (i.e. background module name) module, an AdminModule.php file will be generated under module->admin. This class inherits the CWebModule class. The code for this file is given below. The key The point lies in this document, I hope you will study it carefully:
<?php class AdminModule extends CWebModule { public function init() { // this method is called when the module is being created // you may place code here to customize the module or the application parent::init();//这步是调用main.php里的配置文件 // import the module-level models and componen $this->setImport(array( 'admin.models.*', 'admin.components.*', )); //这里重写父类里的组件 //如有需要还可以参考API添加相应组件 Yii::app()->setComponents(array( 'errorHandler'=>array( 'class'=>'CErrorHandler', 'errorAction'=>'admin/default/error', ), 'admin'=>array( 'class'=>'AdminWebUser',//后台登录类实例 'stateKeyPrefix'=>'admin',//后台session前缀 'loginUrl'=>Yii::app()->createUrl('admin/default/login'), ), ), false); //下面这两行我一直没搞定啥意思,貌似CWebModule里也没generatorPaths属性和findGenerators()方法 //$this->generatorPaths[]='admin.generators'; //$this->controllerMap=$this->findGenerators(); } public function beforeControllerAction($controller, $action) { if(parent::beforeControllerAction($controller, $action)) { $route=$controller->id.'/'.$action->id; if(!$this->allowIp(Yii::app()->request->userHostAddress) && $route!=='default/error') throw new CHttpException(403,"You are not allowed to access this page."); $publicPages=array( 'default/login', 'default/error', ); if(Yii::app()->admin->isGuest && !in_array($route,$publicPages)) Yii::app()->admin->loginRequired(); else return true; } return false; } protected function allowIp($ip) { if(empty($this->ipFilters)) return true; foreach($this->ipFilters as $filter) { if($filter==='*' || $filter===$ip || (($pos=strpos($filter,'*'))!==false && !strncmp($ip,$filter,$pos))) return true; } return false; } } ?>
The init() method of AdminModule is to configure another login instance for the backend, let the front and backend use different CWebUser, and set the backend session prefix to distinguish it from the frontend session (they are stored in the $_SESSION array, you You can print it out and see).
In this way, the front and back logins have been separated, but if you log out at this time, you will find that the front and backends have logged out together. So I found the logout() method and found that it has a parameter $destroySession=true. It turns out that if you just logout(), all sessions will be logged out. If you add a false parameter, only the current login instance will be logged out. session, which is why it is necessary to set the front and back session prefixes. Let’s see how the logout method with the false parameter is set to log out the session:
/** * Clears all user identity information from persistent storage. * This will remove the data stored via {@link setState}. */ public function clearStates() { $keys=array_keys($_SESSION); $prefix=$this->getStateKeyPrefix(); $n=strlen($prefix); foreach($keys as $key) { if(!strncmp($key,$prefix,$n)) unset($_SESSION[$key]); } }
Did you see that you use the matching prefix to log out?
At this point, we can separate the front and back logins and exits. This makes it more like an application, right? Hehe...
I almost forgot to explain:
Yii::app()->user //前台访问用户信息方法 Yii::app()->admin //后台访问用户信息方法
If you don’t understand, take a closer look at the configuration of CWebUser in the front and backend just now.
Attachment 1: WebUser.php code:
<?php class WebUser extends CWebUser { public function __get($name) { if ($this->hasState('__userInfo')) { $user=$this->getState('__userInfo',array()); if (isset($user[$name])) { return $user[$name]; } } return parent::__get($name); } public function login($identity, $duration) { $this->setState('__userInfo', $identity->getUser()); parent::login($identity, $duration); } } ?>
Attachment 2: AdminWebUser.php code
<?php class AdminWebUser extends CWebUser { public function __get($name) { if ($this->hasState('__adminInfo')) { $user=$this->getState('__adminInfo',array()); if (isset($user[$name])) { return $user[$name]; } } return parent::__get($name); } public function login($identity, $duration) { $this->setState('__adminInfo', $identity->getUser()); parent::login($identity, $duration); } } ?>
Attachment 3: Front-end UserIdentity.php code
<?php /** * UserIdentity represents the data needed to identity a user. * It contains the authentication method that checks if the provided * data can identity the user. */ class UserIdentity extends CUserIdentity { /** * Authenticates a user. * The example implementation makes sure if the username and password * are both 'demo'. * In practical applications, this should be changed to authenticate * against some persistent user identity storage (e.g. database). * @return boolean whether authentication succeeds. */ public $user; public $_id; public $username; public function authenticate() { $this->errorCode=self::ERROR_PASSWORD_INVALID; $user=User::model()->find('username=:username',array(':username'=>$this->username)); if ($user) { $encrypted_passwd=trim($user->password); $inputpassword = trim(md5($this->password)); if($inputpassword===$encrypted_passwd) { $this->errorCode=self::ERROR_NONE; $this->setUser($user); $this->_id=$user->id; $this->username=$user->username; //if(isset(Yii::app()->user->thisisadmin)) // unset (Yii::app()->user->thisisadmin); } else { $this->errorCode=self::ERROR_PASSWORD_INVALID; } } else { $this->errorCode=self::ERROR_USERNAME_INVALID; } unset($user); return !$this->errorCode; } public function getUser() { return $this->user; } public function getId() { return $this->_id; } public function getUserName() { return $this->username; } public function setUser(CActiveRecord $user) { $this->user=$user->attributes; } }
Attachment 4: Backend UserIdentity.php code
<?php /** * UserIdentity represents the data needed to identity a user. * It contains the authentication method that checks if the provided * data can identity the user. */ class UserIdentity extends CUserIdentity { /** * Authenticates a user. * The example implementation makes sure if the username and password * are both 'demo'. * In practical applications, this should be changed to authenticate * against some persistent user identity storage (e.g. database). * @return boolean whether authentication succeeds. */ public $admin; public $_id; public $username; public function authenticate() { $this->errorCode=self::ERROR_PASSWORD_INVALID; $user=Staff::model()->find('username=:username',array(':username'=>$this->username)); if ($user) { $encrypted_passwd=trim($user->password); $inputpassword = trim(md5($this->password)); if($inputpassword===$encrypted_passwd) { $this->errorCode=self::ERROR_NONE; $this->setUser($user); $this->_id=$user->id; $this->username=$user->username; // Yii::app()->user->setState("thisisadmin", "true"); } else { $this->errorCode=self::ERROR_PASSWORD_INVALID; } } else { $this->errorCode=self::ERROR_USERNAME_INVALID; } unset($user); return !$this->errorCode; } public function getUser() { return $this->admin; } public function getId() { return $this->_id; } public function getUserName() { return $this->username; } public function setUser(CActiveRecord $user) { $this->admin=$user->attributes; } }
I hope this article will be helpful to everyone’s PHP program design based on the Yii framework.