Authenticating User
===================

Our blog application needs to differentiate between the system owner and guest users. Therefore, we need to implement the [user authentication](http://www.yiiframework.com/doc/guide/topics.auth) 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](http://www.yiiframework.com/doc/guide/basics.namespace). 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()|YiiBase::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]
<?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 `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](http://www.yiiframework.com/doc/guide/database.ar) 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 and a randomly generated salt. When validating the user-entered password, we should compare the hash results, instead. We use the PHP built-in function `crypt()` to hash the password and to validate it, for complete details see the Wiki article [Use crypt() for password storage](http://www.yiiframework.com/wiki/425).

~~~
[php]
class User extends CActiveRecord
{
	......
	public function validatePassword($password)
	{
		return crypt($password,$this->password)===$this->password;
	}

	public function hashPassword($password)
	{
		return crypt($password, $this->generateSalt());
	}
}
~~~

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 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:
>
> ~~~
> [php]
> 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:

~~~
[php]
$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 `tbl_user` table. If we use the database provided by the [blog demo](http://www.yiiframework.com/demos/blog/), 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.

<div class="revision">$Id$</div>