Uwierzytelnianie użytkownika =================== Nasza aplikacja blogu potrzebuje umieć rozróżnić użytkownika systemu od gościa. Dlatego też, potrzebujemy zaimplementować funkcjonalność [uwierzytelniania użytkowników](http://www.yiiframework.com/doc/guide/topics.auth). Jak z pewnością się już zorientowałeś szkielet aplikacji dostarcza już uwierzytelnienia użytkownika poprzez sprawdzanie czy nazwa użytkownika i hasło to jednocześnie `demo` lub `admin`. W części tej zmodyfikujemy odpowiadający temu kod, tak aby uwierzytelnienie odbywało się w oparciu o bazę danych `User`. Uwierzytelnienie użytkownika wykonywane jest w klasie implementującej interfejs [IUserIdentity]. Szkielet aplikacji używa do tego celu klasy `UserIdentity`. Klasa ta znajduje się w pliku `/wwwroot/blog/protected/components/UserIdentity.php`. > Tip|Wskazówka: Dla wygody, nazwa pliku klasy musi być taka sama jak odpowiadająca mu nazwa klasy i zakończona rozszerzeniem `.php`. Używając tej konwencji, można odnosić się do klasy używając [aliasów ścieżek](http://www.yiiframework.com/doc/guide/basics.namespace). Na przykład, możemy odnosić się do klasy `UserIdentity` przy użyciu aliasu `application.components.UserIdentity`. Wiele API w Yii jest w stanie rozpoznawać aliasy ścieżek (np. [Yii::createComponent()|YiiBase::createComponent]), dodatkowo używanie aliasów, pozwala uniknąć konieczności umieszczania absolutnych ścieżek do plików w kodzie. Występowanie tych ostatnich często powoduje problemy podczas wdrażania aplikacji. Zmodyfikujemy klasę `UserIdentity` w następujący sposób: ~~~ [php] 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; } } ~~~ W metodzie `authenticate(), używamy klasy `User` do wyszukiwania wiersza danych w tabeli `tbl_user`, którego kolumna `username` posiada tą samą wartość co nazwa użytkownika, bez uwzględnienia wielkości liter. Przypominamy, że klasa `User` została utworzona za pomocą narzędzia `gii` w poprzedniej części. Ponieważ klasa `User` dziedziczy z [CActiveRecord], możemy wykorzystać [funkcjonalność rekordu aktywnego](http://www.yiiframework.com/doc/guide/database.ar) i uzyskać dostęp do tabeli `User` w obiektowy (OOP) sposób. W celu sprawdzenia czy użytkownik wprowadził prawidłowe hasło, wywołujemy metodę `validatePassword` klasy użytkownika `User`. Musimy zmodyfikować plik `/wwwroot/blog/protected/models/User.php` w następujący sposób. Zauważ, że zamiast przechowywać hasło tekstowo w bazie danych, przechowujemy rezultat haszowania hasła oraz losowo wygenerowany klucz soli. Podczas sprawdzania poprawności hasła wprowadzonego przez użytkownika powinniśmy użyć do porównywania rezultatu haszowania hasła zamiast samego hasła. ~~~ [php] 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); } } ~~~ W klasie `UserIdentity` nadpisujemy również metodę `getId()`, która zwraca wartość `id` dla znalezionego w tabeli `tbl_user` użytkownika. Poprzednia implementacja zwracała nazwę użytkownika (username). Obie właściwości: nazwa użytkownika `username` oraz jego ID `id` będą zachowane w sesji użytkownika user oraz będzie można do nich uzyskać dostęp poprzez `Yii::app()->user` z dowolnego miejsca w naszym kodzie. > Tip|Wskazówka: W klasie `UserIdentity` odnosimy się do klasy [CUserIdentity] bez bezpośredniego włączania odpowiadającego jej pliku klasy. Dzieje się tak, gdyż klasa [CUserIdentity] jest rdzenną klasą dostarczaną przez framework Yii. Yii automatycznie załączy plik klasy dla każdej z rdzennych klas, podczas pierwszego odniesienia się do niej. > >Dokładnie to samo zrobimy z klasą `User`. Dzieje się tak ponieważ plik klasy `User` znajduje się w katalogu `/wwwroot/blog/protected/models`, który został dodany do `include_path` PHP zgodnie z następującymi liniami znajdującymi się w konfiguracji aplikacji: > > ~~~ > [php] > return array( > ...... > 'import'=>array( > 'application.models.*', > 'application.components.*', > ), > ...... > ); > ~~~ > > Powyższa konfiguracja mówi, iż każda z klas, której plik klasy znajduje się w katalogu `/wwwroot/blog/protected/models` lub też `/wwwroot/blog/protected/components` będzie automatycznie załączony jeśli odnosimy się do klasy po raz pierwszy. Klasa `UserIdentity` jest używana przede wszystkim w klasie `LoginForm` w celu uwierzytelnienia użytkownika bazującego na wprowadzonej na stronie logowania nazwie użytkownika i haśle. Następujący fragment kodu pokazuje w jaki sposób klasa `UserIdentity` jest używana: ~~~ [php] $identity=new UserIdentity($username,$password); $identity->authenticate(); switch($identity->errorCode) { case UserIdentity::ERROR_NONE: Yii::app()->user->login($identity); break; ...... } ~~~ > Info|Info: Ludzie często mylą tożsamość (UserIdentity) i komponent użytkownika aplikacji `user`. Pierwsze (tożsamość) reprezentuje sposób przeprowadzania uwierzytelnienia, druga zaś używana jest do reprezentowania informacji związanych z aktualnym użytkownikiem. Aplikacja może posiadać tylko jeden komponent użytkownika `user`, ale może posiadać jedną lub więcej klas tożsamościowych w zależności od rodzaju wpieranego sposobu uwierzytelniania. Po uwierzytelnieniu, instancja zawierająca tożsamość może przekazać swoje informacje o stanie do komponentu użytkownika `user`, tak, że ten jest globalnie dostępny poprzez właściwość `user`. W celu przetestowania zmodyfikowanej klasy `UserIdentity`, możemy otworzyć adres URL `http://www.example.com/blog/index.php` i spróbować zalogować się przy użyciu nazwy użytkownika oraz hasła przechowywanego w tabeli `tbl_user`. Jeśli użyjemy bazy danych dostarczonej przez [demo blogu](http://www.yiiframework.com/demos/blog/), powinniśmy być w stanie zalogować się przy użyciu nazwy użytkownika `demo` oraz hasła `demo`. Zauważ, że ten system blogowy nie dostarcza funkcjonalności zarządzania użytkownikami. W rezultacie użytkownik nie może zmienić swojego konta czy też stworzyć nowego poprzez interfejs sieciowy. Funkcjonalność zarządzania użytkownikami może zostać rozważona jako przyszłe rozszerzenie dla naszej aplikacji.