Our blog application needs to differentiate between the system owner and guest users. Therefore, we need to implement the user authentication feature.
As you may have found that the skeleton application already provides user authentication by checking if the username and password are both demo
or admin
. In this section, we will modify the corresponding code so that the authentication is done against the User
database table.
User authentication is performed in a class implementing the IUserIdentity interface. The skeleton application uses the UserIdentity
class for this purpose. The class is stored in the file /wwwroot/blog/protected/components/UserIdentity.php
.
Tip: By convention, the name of a class file must be the same as the corresponding class name suffixed with the extension
.php
. Following this convention, one can refer to a class using a path alias. For example, we can refer to theUserIdentity
class with the aliasapplication.components.UserIdentity
. Many APIs in Yii can recognize path aliases (e.g. Yii::createComponent()), and using path aliases avoids the necessity of embedding absolute file paths in the code. The existence of the latter often causes trouble when we deploy an application.
We modify the UserIdentity
class as follows,
class UserIdentity extends CUserIdentity { private $_id; public function authenticate() { $username=strtolower($this->username); $user=User::model()->find('LOWER(username)=?',array($username)); if($user===null) $this->errorCode=self::ERROR_USERNAME_INVALID; else if(!$user->validatePassword($this->password)) $this->errorCode=self::ERROR_PASSWORD_INVALID; else { $this->_id=$user->id; $this->username=$user->username; $this->errorCode=self::ERROR_NONE; } return $this->errorCode==self::ERROR_NONE; } public function getId() { return $this->_id; } }
In the authenticate()
method, we use the User
class to look for a row in the tbl_user
table whose username
column
is the same as the given username in a case-insensitive manner. Remember that the User
class was created using the gii
tool in the prior section. Because the User
class extends from CActiveRecord, we can exploit
the ActiveRecord feature to access the tbl_user
table in an OOP fashion.
In order to check if the user has entered a valid password, we invoke the validatePassword
method of the User
class.
We need to modify the file /wwwroot/blog/protected/models/User.php
as follows. Note that instead of storing the plain
password in the database, we store a hash of the password. When validating the user-entered password, we should compare
the hash results, instead. We use the Yii built-in CPasswordHelper to hash the password and to validate it.
class User extends CActiveRecord
{
......
public function validatePassword($password)
{
return CPasswordHelper::verifyPassword($password,$this->password);
}
public function hashPassword($password)
{
return CPasswordHelper::hashPassword($password);
}
}
In the UserIdentity
class, we also override the getId()
method which returns the id
value of the user found in the tbl_user
table. The parent implementation would return the username, instead. Both the username
and id
properties will be stored in the user session and may be accessed via Yii::app()->user
from anywhere in our code.
Tip: In the
UserIdentity
class, we reference the class CUserIdentity without explicitly including the corresponding class file. This is because CUserIdentity is a core class provided by the Yii framework. Yii will automatically include the class file for any core class when it is referenced for the first time.We also do the same with the
User
class. This is because theUser
class file is placed under the directory/wwwroot/blog/protected/models
which has been added to the PHPinclude_path
according to the following lines found in the application configuration:return array( ...... 'import'=>array( 'application.models.*', 'application.components.*', ), ...... );
The above configuration says that any class whose class file is located under either
/wwwroot/blog/protected/models
or/wwwroot/blog/protected/components
will be automatically included when the class is referenced for the first time.
The UserIdentity
class is mainly used by the LoginForm
class to authenticate a user based on the username and password input collected from the login page. The following code fragment shows how UserIdentity
is used:
$identity=new UserIdentity($username,$password);
$identity->authenticate();
switch($identity->errorCode)
{
case UserIdentity::ERROR_NONE:
Yii::app()->user->login($identity);
break;
......
}
Info: People often get confused about identity and the
user
application component. The former represents a way of performing authentication, while the latter is used to represent the information related with the current user. An application can only have oneuser
component, but it can have one or several identity classes, depending on what kind of authentication it supports. Once authenticated, an identity instance may pass its state information to theuser
component so that they are globally accessible viauser
.
To test the modified UserIdentity
class, we can browse the URL http://www.example.com/blog/index.php
and try logging in with the username and password that we store in the tbl_user
table. If we use the database provided by the blog demo, we should be able to login with username demo
and password demo
. Note that this blog system does not provide the user management feature. As a result, a user cannot change his account or create a new one through the Web interface. The user management feature may be considered as a future enhancement to the blog application.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.