Also available in these languages:
English日本語polskiРусский简体中文

Authenticating User

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 the UserIdentity class with the alias application.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,

<?php
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 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 yiic tool in the prior section. Because the User class extends from CActiveRecord, we can exploit the ActiveRecord feature to access the 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 the hash result of the password and a randomly generated salt key. When validating the user-entered password, we should compare the hash results, instead.

class User extends CActiveRecord
{
    ......
    public function validatePassword($password)
    {
        return $this->hashPassword($password,$this->salt)===$this->password;
    }
 
    public function hashPassword($password,$salt)
    {
        return md5($salt.$password);
    }
}

In the UserIdentity class, we also override the getId() method which returns the id value of the user found in the 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 the User class file is placed under the directory /wwwroot/blog/protected/models which has been added to the PHP include_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 one user 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 the user component so that they are globally accessible via user.

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 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.

$Id: prototype.auth.txt 1677 2010-01-07 20:29:26Z qiang.xue $
If you find any typos or errors in the tutorial, please create a Yii ticket to report it. If it is a translation error, please create a Yiidoc ticket, instead. Thank you.

Total 7 comments:

#143
Database in Model
by yogesh_sharma at 3:01am on March 26, 2009.

Could any one provide the example how to define the database in the model file.

#169
here u go
by hint63 at 4:14pm on April 5, 2009.

'db'=>array( 'class'=>'CDbConnection', 'connectionString'=>'mysql:host=localhost;dbname=dbname', 'username'=>'dbuser', 'password'=>'yourDBpassword', ),

#249
Questions about username and ID
by tim at 4:53pm on April 29, 2009.

Does anyone know where / how the username and ID of the user get stored in the session? I'm trying to track down where those values get stored in the session because I have other identity values I'd like to store in the session. I checked the base class CUserIdentity and didn't see it there either. Thanks!

#349
Re. Questions about username and ID
by wyldie at 6:03pm on June 2, 2009.

You could always use $this->setState('dummy_role', $value);

And check it with Yii::app()->user->getState('dummy_role');

#378
why set explicity the username to be in the session?
by skyblaze at 6:33am on June 12, 2009.

Knowing from the docs that the identity class automatically pass the username to the user object (and so store it in the session) why in this code we explicitely set the identity class username property?

#1763
LOWER(username)
by thinkingspace at 8:21am on August 5, 2010.

If like me you are using a MySQL DB you might be wondering why the LOWER(username) is needed. I believe that it is because SQLite by default is case sensitive when matching values.

#1803
Missing method generateSalt in User Model
by jwerner at 8:49am on August 17, 2010.

I think one needs to also add the generateSalt method in the user method:

/**
 * Generates a salt that can be used to generate a password hash.
 * @return string the salt
 */
protected function generateSalt()
{
    return uniqid('',true);
}

Your Comment:

You may enter comment using Markdown syntax.

Please login with your forum account.
Note: you must have at least ONE forum post with your account.