Describe the implementation of the login function in the Yii framework of PHP in detail.
Yii Login Mechanism
Yii provides the most basic user login mechanism when generating an application. We use Yii to generate a new application and enter the protected/components directory. We can see the UserIdentity. php file. There is only one public function in the UserIdentity class:
public function authenticate() { $users=array( // username => password 'demo'=>'demo', 'admin'=>'admin', ); if(!isset($users[$this->username])) $this->errorCode=self::ERROR_USERNAME_INVALID; elseif($users[$this->username]!==$this->password) $this->errorCode=self::ERROR_PASSWORD_INVALID; else $this->errorCode=self::ERROR_NONE; return !$this->errorCode; }
This class is in components and will be loaded at the beginning of the application for the most basic user verification. You can see that, at the beginning, this function simply defines two users, demo and admin, And the password is only demo and admin. If your users are limited, you can directly modify and add users here. We will talk about it later. The if else in the function is used to check whether the user name and password are valid. if an error occurs, errors such as ERROR_USERNAME_INVALID and ERROR_PASSWORD_INVALID are generated. In general, real user name and password verification is performed here, and the basic logic after login is processed.
The login control process cannot be seen from the perspective of this class. Following the Model/Control/View principles, we can see that the login process is reflected in these three aspects. First, go to the Models folder and you can see a LoginForm class file. This class inherits from CFormModel, which is a form model derived class and encapsulates login data and business logic. The core functions are as follows:
/*** Authenticates the password. * This is the 'authenticate' validator as declared in rules (). */public function authenticate ($ attribute, $ params) {$ this-> _ identity = new UserIdentity ($ this-> username, $ this-> password); if (! $ This-> _ identity-> authenticate () $ this-> addError ('Password', 'user name or password error ');} /*** Logs in the user using the given username and password in the model. * @ return boolean whether login is successful */public function login () {if ($ this-> _ identity = null) {$ this-> _ identity = new UserIdentity ($ this-> username, $ this-> password); $ this-> _ identity-> authenticate ();} if ($ this-> _ identity-> errorCode = UserIden Tity: ERROR_NONE) {$ duration = $ this-> rememberMe? 3600*24*30: 0; // 30 days Yii: app ()-> user-> login ($ this-> _ identity, $ duration); return true ;} else return false ;}
Here, authenticate uses the UserIdentity class to verify the user name and password. The login function checks whether the user identity has been set and whether the error code is null. Finally, the login function provided by Yii is used to log on. $ Duration can be used to set the validity period of an identity.
Let's look at Control. In siteControler, there is an action about logon, that is, actionLogin. The function is as follows:
/** * Displays the login page */ public function actionLogin() { if (!defined('CRYPT_BLOWFISH')||!CRYPT_BLOWFISH) throw new CHttpException(500,"This application requires that PHP was compiled with Blowfish support for crypt()."); $model=new LoginForm; // if it is ajax validation request if(isset($_POST['ajax']) && $_POST['ajax']==='login-form') { echo CActiveForm::validate($model); Yii::app()->end(); } // collect user input data if(isset($_POST['LoginForm'])) { $model->attributes=$_POST['LoginForm']; // validate user input and redirect to the previous page if valid if($model->validate() && $model->login()) $this->redirect(Yii::app()->user->returnUrl); } // display the login form $this->render('login',array('model'=>$model)); }
The login action is based on the LoginForm to verify the form of the POST or render a New login page.
Finally, the view File is login. php In the site folder, which is the login interface you see.
After sorting out, we can clearly see that Yii's user login logic processing, after you enter the user name and password on the login interface, the form will POST the data to the site/login action, loign instantiates a LoginForm form model and performs logon Detection Based on the validate and login functions in the model. validate verifies the form data according to the rules of the rule. The authentication of password requires the authenticate function, the authenticate and login functions are based on UserIdentity's authenticate function. Therefore, if we change the login logic, neither LgoinForm nor loginaction can be modified. simply change the authenticate function of UserIdentity.
The above analysis is the logic processing code automatically generated by Yii for user login. It looks pretty decent, doesn't it? However, our system generally needs to support access by many users. It is obviously irrational to simply list the user names and passwords in the Code. To be more mature, please ask the database to help us manage them. Suppose we create an admin table in our database by following the Mysql statement below:
Drop table if exists 'admin'; create table 'admin' ('admin _ id' int unsigned not null auto_increment comment 'Primary key', 'username' varchar (32) not null comment 'login name', 'psw' char (40) not null comment' login password (twice sha1) ', 'Nick' varchar (64) not null comment 'nicknames ', 'add _ time' datetime not null comment 'creation time', 'login _ time' datetime null comment' recent logon time ', unique key ('username'), primary key ('admin _ id') engine = innodb default charset = utf8 comment = 'administrator table ';
After the Mysql table is created, we use gii to generate the admin Model. Then we can return to UserIdentity. php In our original Component to rewrite the authenticate function to verify the user name and password. For the sake of security, the password is encrypted twice, so the collected password is encrypted twice, then, in the Admin we created, find out whether there is a user corresponding to the username entered in the form, and then compare the encrypted password, if all the information is passed, you can set the user's common information from the setState function to the user field of Yii, such as $ this-> setState ('Nick ', $ user-> nick); after this sentence, you can directly access the nickname of the current login user through Yii: app ()-> user-> nick, instead of querying the database. While $ user-> login_time = date ('Y-m-d H: I: s') is used to update the user login time, save the statement to the database.
public function authenticate() { if(strlen($this->password) > 0) $this->password = sha1(sha1($this->password)); $user = Admin::model()->findByAttributes(array('username' => $this->username)); if($user == null) $this->errorCode=self::ERROR_USERNAME_INVALID; elseif( !($user instanceof Admin) || ($user->psw != $this->password) ) $this->errorCode=self::ERROR_PASSWORD_INVALID; else { $this->setState('admin_id', $user->admin_id); $this->setState('nick', $user->nick); $this->setState('username', $user->username); $user->login_time = date('Y-m-d H:i:s'); $user->save(); $this->errorCode=self::ERROR_NONE; } return !$this->errorCode; }
If you want to modify the login interface, enter the login in the site folder in the view. php, let it look as you want, so that our login process is complete. Is it very convenient to have Yii ~
Set automatic login
The principle of automatic logon is simple. It is mainly implemented using cookies.
During the first logon, if the logon succeeds and the next automatic logon is selected, the user's authentication information will be saved to the cookie. The cookie is valid for one year or several months.
The next time you log on, first determine whether the cookie stores user information. If so, use the user information stored in the cookie to log on,
Configure the User component
First, set the user component in the components of the configuration file.
'user' => [ 'identityClass' => 'app\models\User', 'enableAutoLogin' => true, ],
We can see that enableAutoLogin is used to determine whether to enable the automatic login function, which is irrelevant to the next automatic login on the interface.
If enableAutoLogin is set to true, the user information is stored in the cookie and the cookie is valid for 3600*24*30 seconds, for next login
Now let's take a look at how Yii is implemented.
I. First Login to save the cookie
1. login
public function login($identity, $duration = 0) { if ($this->beforeLogin($identity, false, $duration)) { $this->switchIdentity($identity, $duration); $id = $identity->getId(); $ip = Yii::$app->getRequest()->getUserIP(); Yii::info("User '$id' logged in from $ip with duration $duration.", __METHOD__); $this->afterLogin($identity, false, $duration); } return !$this->getIsGuest(); }
Here, it is a simple login, and then execute the switchIdentity method to set authentication information.
2. Set authentication information for switchIdentity
public function switchIdentity($identity, $duration = 0) { $session = Yii::$app->getSession(); if (!YII_ENV_TEST) { $session->regenerateID(true); } $this->setIdentity($identity); $session->remove($this->idParam); $session->remove($this->authTimeoutParam); if ($identity instanceof IdentityInterface) { $session->set($this->idParam, $identity->getId()); if ($this->authTimeout !== null) { $session->set($this->authTimeoutParam, time() + $this->authTimeout); } if ($duration > 0 && $this->enableAutoLogin) { $this->sendIdentityCookie($identity, $duration); } } elseif ($this->enableAutoLogin) { Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie)); } }
This method is important. You also need to call this method when exiting.
This method has three main functions:
Set the session Validity Period
If the cookie validity period is greater than 0 and automatic logon is allowed, the user's authentication information is saved to the cookie.
If Automatic Logon is allowed, the cookie information is deleted. This is called when you exit. $ Identity passed in when exiting is null
protected function sendIdentityCookie($identity, $duration) { $cookie = new Cookie($this->identityCookie); $cookie->value = json_encode([ $identity->getId(), $identity->getAuthKey(), $duration, ]); $cookie->expire = time() + $duration; Yii::$app->getResponse()->getCookies()->add($cookie); }
The user information stored in the cookie contains three values:
- $ Identity-> getId ()
- $ Identity-> getAuthKey ()
- $ Duration
GetId () and getAuthKey () are in the IdentityInterface interface. We also know that when setting the User component, this User Model must implement the IdentityInterface interface. Therefore, you can get the first two values in the User Model. The third value is the cookie validity period.
Ii. Automatic Login from cookie
We know from the above that the user's authentication information has been stored in the cookie, so the next time you directly retrieve the information from the cookie and then set it.
1. AccessControl user access control
Yii provides AccessControl to determine whether a user is logged on. If this happens, you do not need to judge it in every action.
public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'only' => ['logout'], 'rules' => [ [ 'actions' => ['logout'], 'allow' => true, 'roles' => ['@'], ], ], ], ]; }
2. getIsGuest and getIdentity determine whether to authenticate the user
IsGuest is the most important attribute in the automatic logon process.
In the above AccessControl access control, the IsGuest attribute is used to determine whether a user is authenticated. Then, in the getIsGuest method, getIdentity is called to obtain user information. If it is not empty, it indicates that the user is authenticated, otherwise, it is a visitor (not logged on ).
public function getIsGuest($checkSession = true) { return $this->getIdentity($checkSession) === null; } public function getIdentity($checkSession = true) { if ($this->_identity === false) { if ($checkSession) { $this->renewAuthStatus(); } else { return null; } } return $this->_identity; }
3. renewAuthStatus: Regenerate user authentication information
protected function renewAuthStatus() { $session = Yii::$app->getSession(); $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null; if ($id === null) { $identity = null; } else { /** @var IdentityInterface $class */ $class = $this->identityClass; $identity = $class::findIdentity($id); } $this->setIdentity($identity); if ($this->authTimeout !== null && $identity !== null) { $expire = $session->get($this->authTimeoutParam); if ($expire !== null && $expire < time()) { $this->logout(false); } else { $session->set($this->authTimeoutParam, time() + $this->authTimeout); } } if ($this->enableAutoLogin) { if ($this->getIsGuest()) { $this->loginByCookie(); } elseif ($this->autoRenewCookie) { $this->renewIdentityCookie(); } } }
This part first judges the user through the session, because the user has already existed in the session after login. Then, you can use the cookie information to log on automatically.
4. log on to loginByCookie through the saved Cookie Information
protected function loginByCookie() { $name = $this->identityCookie['name']; $value = Yii::$app->getRequest()->getCookies()->getValue($name); if ($value !== null) { $data = json_decode($value, true); if (count($data) === 3 && isset($data[0], $data[1], $data[2])) { list ($id, $authKey, $duration) = $data; /** @var IdentityInterface $class */ $class = $this->identityClass; $identity = $class::findIdentity($id); if ($identity !== null && $identity->validateAuthKey($authKey)) { if ($this->beforeLogin($identity, true, $duration)) { $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0); $ip = Yii::$app->getRequest()->getUserIP(); Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__); $this->afterLogin($identity, true, $duration); } } elseif ($identity !== null) { Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__); } } } }
First read the cookie value, and then $ data = json_decode ($ value, true); deserialization into an array.
From the code above, we can know that all three values must have values for automatic logon. In addition, you must implement the findIdentity and validateAuthKey methods in the User Model.
After logging on, You can reset the cookie validity period so that it works together.
$this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
3. log out
public function logout($destroySession = true) { $identity = $this->getIdentity(); if ($identity !== null && $this->beforeLogout($identity)) { $this->switchIdentity(null); $id = $identity->getId(); $ip = Yii::$app->getRequest()->getUserIP(); Yii::info("User '$id' logged out from $ip.", __METHOD__); if ($destroySession) { Yii::$app->getSession()->destroy(); } $this->afterLogout($identity); } return $this->getIsGuest(); } public function switchIdentity($identity, $duration = 0) { $session = Yii::$app->getSession(); if (!YII_ENV_TEST) { $session->regenerateID(true); } $this->setIdentity($identity); $session->remove($this->idParam); $session->remove($this->authTimeoutParam); if ($identity instanceof IdentityInterface) { $session->set($this->idParam, $identity->getId()); if ($this->authTimeout !== null) { $session->set($this->authTimeoutParam, time() + $this->authTimeout); } if ($duration > 0 && $this->enableAutoLogin) { $this->sendIdentityCookie($identity, $duration); } } elseif ($this->enableAutoLogin) { Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie)); } }
When you exit, set the current authentication to null, and then delete the related cookie information if the automatic logon function is used.