Аутентифікація користувача
==========================

Наш додаток повинен розрізняти власника системи та гостей. Тому
ми повинні реалізувати функцію
[користувальницької аутентифікації](/doc/guide/uk/topics.auth).

Ви, можливо, помітили, що каркас додатка вже реалізує аутентифікацію, 
перевіряючи, чи є імʼя користувача та пароль значеннями `demo` та `admin`. 
У цьому розділі ми змінимо відповідний код так, щоб аутентифікація
відбувалася за допомогою таблиці `User` БД.

Аутентифікація користувача виконується у класі, який реалізує інтерфейс
[IUserIdentity]. Для цієї мети каркас додатка використовує клас `UserIdentity`.
Клас знаходиться у файлі `/wwwroot/blog/protected/components/UserIdentity.php`.

> Tip|Підказка: У відповідності з угодою, назва файла класу має бути
> такою ж, як імʼя класу плюс розширення `.php`. Можна звернутися до класу, використовуючи
> [псевдонім шляху](/doc/guide/uk/basics.namespace). Наприклад, ми
> можемо звернутися до класу `UserIdentity` використовуючи псевдонім
> `application.components.UserIdentity`. Багато методів API у Yii можуть розпізнати
> псевдоніми шляху (наприклад, [Yii::createComponent()|YiiBase::createComponent]).
> Це дозволяє уникнути використання абсолютних шляхів у коді, які створюють
> неприємності при розгортанні додатка.

Модифікуємо клас `UserIdentity` наступним чином:

~~~
[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;
	}
}
~~~

У методі `authenticate()` ми використовуємо клас `User` для пошуку рядка у таблиці `tbl_user`, 
в якій значення поля `username` таке ж, як отримане імʼя користувача без урахування регістра. 
Памʼятайте, що клас `User` був створений, використовуючи інструмент `gii` у попередньому розділі. 
Оскільки клас `User` успадковується від класу [CActiveRecord], ми можемо використовувати
[можливості ActiveRecord](/doc/guide/uk/database.ar) для того, щоб звертатися до таблиці `tbl_user` в ОО манері.

Для того, щоб перевірити чи ввів користувач правильний пароль, ми викликаємо метод `validatePassword` класу `User`. 
Нам необхідно змінити файл `/wwwroot/blog/protected/models/User.php` як показано нижче. 
Відзначимо, що замість зберігання пароля у БД у явному вигляді, 
ми використовуємо хеш від пароля та ключа (солі), що генерується випадковим чином.
При перевірці введеного користувачем пароля, замість порівняння паролів, ми повинні порівнювати хеші. 
Ми використовуємо стандартну PHP-функцію `crypt()` для хешування і перевірки пароля. 
Ознайомтеся з вікі-статтею [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());
	}
}
~~~

У класі `UserIdentity` ми також перевизначаємо метод `getId()`, 
який повертає значення `id` користувача, знайденого у таблиці `tbl_user`. 
Батьківська реалізація повернула б імʼя користувача замість `id`. 
І `username` і `id` будуть збережені в сесії і доступні через `Yii::app()->user` 
у будь-якому місці нашого коду.

> Tip|Підказка: У класі `UserIdentity` ми використовуємо [CUserIdentity]
> без явного підключення відповідного файлу. Це можливо тому, що
> [CUserIdentity] — один з класів ядра фреймворку Yii. Yii буде
> автоматично підключати файл класу для будь-якого класу ядра, коли до нього
> звернуться вперше. Те ж можливо з класом `User`, тому що він розташований у директорії
> `/wwwroot/blog/protected/models`, яка була додана до параметру
> `include_path` PHP в конфігурації додатка наступним чином:
>
> ~~~
> [php]
> return array(
>     …
>     'import'=>array(
>         'application.models.*',
>         'application.components.*',
>     ),
>     …
> );
> ~~~
>
> Конфігурація вище говорить, що будь-який клас, файл якого розташований
> в директорії `/wwwroot/blog/protected/models` або
> `/wwwroot/blog/protected/components`, буде автоматично підключений, коли до
> класу звернуться вперше.

Клас `UserIdentity` використовується класом `LoginForm` для аутентифікації користувача, 
заснованої на введених імені та паролі, отриманих на сторінці входу в систему. 
Наступний фрагмент коду показує як використовується клас `UserIdentity`:

~~~
[php]
$identity=new UserIdentity($username,$password);
$identity->authenticate();
switch($identity->errorCode)
{
	case UserIdentity::ERROR_NONE:
		Yii::app()->user->login($identity);
		break;
	…
}
~~~


> Info|Інформація: Люди часто плутаються в ідентифікації (identity) та компоненті
> додатка `user`. Перша представляє спосіб виконання аутентифікації, у той
> час як останній використовується, щоб надати інформацію, повʼязану з
> поточним користувачем. У додатка може бути тільки один компонент `user`,
> але один або кілька класів ідентифікації, в залежності від того, яку
> аутентифікацію підтримує додаток. При аутентифікації,
> екземпляр ідентифікації може передати деяку інформацію компоненту `user`.
> Ця інформація буде глобально доступна через компонент `user`.

Щоб перевірити змінений клас `UserIdentity`, ми можемо відкрити адресу
`http://www.example.com/blog/index.php` і спробувати увійти з імʼям
користувача та паролем, які ми зберігаємо у таблиці `tbl_user`.
Якщо ми використовуємо базу даних, надану
[демонстраційною версією блогу](http://www.yiiframework.com/demos/blog/),
ми можемо увійти з імʼям користувача `demo` і паролем `demo`. 
Відзначимо, що ця система блогу не забезпечує функцію управління користувачами. 
Тому користувач не може змінити свій обліковий запис або створити новий через веб-інтерфейс. 
Функцію управління користувачами можна розглядати як майбутнє розширення до додатка блогу.
