Uwierzytelnienie i autoryzacja

Uwierzytelnienie oraz autoryzacja są wymagane dla stron WWW, które powinny mieć ograniczony dostęp dla pewnych osób. "Uwierzytelnienie" dotyczy weryfikacji czy ktoś jest tym za kogo się podaje. Zazwyczaj używa do tego nazwę użytkownika oraz hasło, aczkolwiek może zawierać również inne metody reprezentujące tożsamość, takie jak karta inteligentna (mikroprocesorowa), odciski palców itp. "Autoryzacja" jest znajdywaniem czy osoba raz zidentyfikowana (np. uwierzytelniona), posiada uprawnienia do posługiwania się określonym zasobem. Zazwyczaj determinowane jest to poprzez stwierdzanie, czy ta osoba posiada konkretną rolę, która gwarantuje dostęp do zasobu.

Yii posiada wbudowany framework uwierzytelnienia/autoryzacji (auth), który jest łatwy w użyciu i może być dostosowywany do konkretnych potrzeb.

Centralnym miejscem we frameworku auth w Yii jest predefiniowany komponent użytkownika aplikacji (ang. user application component), który jest obiektem implementującym interfejs IWebUser. Component użytkownika reprezentuje stałą informację o tożsamości aktualnego użytkownika. Możemy uzyskać do niej dostęp w każdym miejscu poprzez użycie Yii::app()->user.

Używając komponentu użytkownika możemy sprawdzić czy użytkownik jest zalogowany, czy też nie, poprzez CWebUser::isGuest; możemy zalogować lub wylogować użytkownika; możemy sprawdzić, czy użytkownik może wykonywać określone operacje poprzez wywołanie CWebUser::checkAccess; oraz możemy również otrzymać unikalny identyfikator oraz inne trwałe informacje dotyczące tożsamości użytkownika.

1. Definiowanie klasy tożsamości

Jak wspomniano wcześniej, uwierzytelnienie dotyczy sprawdzania tożsamości użytkownika. Typowa implementacja uwierzytelnienia w aplikacji sieciowej zazwyczaj używa kominacji nazwy użytkownika oraz hasła w celu sprawdzenia tożsamości użytkownika. Jednakże, może ona zawierać różne metody a także różne implementacj moga być wymagane. Aby dostosować się do różnych metod uwierzytelniania, framework auth Yii wprowadza klasę tożsamości.

Główną pracą w definiowaniu klasy tożsamości jest implementacja metody IUserIdentity::authenticate. Metoda ta jest używana do hermetyzacji szczegółów podejścia do uwierzytelnienia. Klasa tożsamości może również deklarować dodatkowe informacje o tożsamości, które muszą trwać podczas sesji użytkownika.

Przykład

W przykładzie tym, używamy klasy tożsamości do zademonstrowania podejścia bazodanowego do tematu uwierzytelnienia. Jest to bardzo typowe dla wieli aplikacji sieciowych. Użytkownik wprowadza jego nazwę oraz hasło do formularza logowania, my następnie spradzimy poprawność tych danych używając rekordu aktywnego, porównując z danymi z tabeli użytkowników. W tym jednym przykładzie, demonstrujemy kilka rzeczy:

  1. Implementację metody authenticate() w celu spradzenia poprawności wprowadzonych danych logowania.
  2. Nadpisanie metody CUserIdentity::getId() w celu zwrócenia właściwości _id, gdyż domyślnie implementacja ta zwraca jako ID nazwę użytkownika.
  3. Uzyciu metody setState() (CBaseUserIdentity::setState) w celu zademonstrowania przechowywania pozostałych informacji, które mogą zostać łatwo zwrócone przy kolejnych żądaniach.
class UserIdentity extends CUserIdentity
{
    private $_id;
    public function authenticate()
    {
        $record=User::model()->findByAttributes(array('username'=>$this->username));
        if($record===null)
            $this->errorCode=self::ERROR_USERNAME_INVALID;
        else if($record->password!==md5($this->password))
            $this->errorCode=self::ERROR_PASSWORD_INVALID;
        else
        {
            $this->_id=$record->id;
            $this->setState('title', $record->title);
            $this->errorCode=self::ERROR_NONE;
        }
        return !$this->errorCode;
    }
 
    public function getId()
    {
        return $this->_id;
    }
}

Kiedy opiszemy logowanie i wylogowywanie w następnych rozdziałach, zobaczymy, że przekazujemy tą klasę rożsamości do metody logowania użytkownika. Pozostałe informacje, które zapisujemy w stanach (poprzez wywołanie CBaseUserIdentity::setState) będą przekazane do kalsy CWebUser, która z kolei zapisze je w nośniku trwałych danych, np. takim jak sesja. Informacje te mogą być później dostępne jak właściwości CWebUser. W naszym przykładzie, przechowujemy informację o tytule użytkownika poprzez $this->setState('title', $record->title);. Gdy już zakończymy proces logowania, możemy uzyskać informację o tytule title użytkownika poprzez proste użycie Yii::app()->user->title.

W następnym przykładzie sprawdzimy poprawność użytkownika i hasła porównując je z tabelą użytkowników w bazie danych przy użyciu Rekordu Aktywnego. Możemy również nadpisać metodę getId aby zwracała zmienną _id, która jest ustawiana podczas uwierzytelniania (domyślna implementacja zwróci nazwę użytkownika jako ID). Podczas uwierzytelniania zapisujemy otrzymaną informację o tytule title w stanie o tej samej nazwie poprzez wywołanie metody CBaseUserIdentity::setState.

Info: Domyślnie CWebUser używa sesji jako trwałego miejsca składowania informacji o tożsamości użytkownika. Jeśli logowanie z użyciem ciasteczek jest udostępnione (poprzez ustawienie wartości CWebUser::allowAutoLogin jako true), informacje o tożsamości użytkownika mogą także zostać zapisane w ciasteczku. Upewnij się, że nie zadeklarowałeś ważnych danych (np. hasła) jako wartości trwałe.

2. Logowanie i wylogowanie

Teraz gdy widzieliśmy przykład tworzenia klasy tożsamości, użyjemy tego aby ułatwić implementację akcji naszych akcji logowania i wylogowania. Następujący kod demonstruje jak można to uczynić:

// logowanie użytkownika za pomocą nazwy użytkownika oraz hasła
$identity=new UserIdentity($username,$password);
if($identity->authenticate())
    Yii::app()->user->login($identity);
else
    echo $identity->errorMessage;
......
// wylogowanie aktualnego użytkownika
Yii::app()->user->logout();

Tutaj utworzyliśmy nowy obiekt UserIdentity i przekazaliśmy mu dane uwierzytelniające (np. nazwę $username i hasło $password podane przez użytkownika) do jego konstruktora. Następnie wołamy po prostu metodę authenticate(). Jeśli zakończy się ona sukcesem, przekazujemy informację o tożsamości do metody CWebUser::login, która przechowa informację o tożsamości w trwałym nośniku danych (domyślnie sesja PHP) w celu zwrócenia ich w następnych żądaniach. Jeśli uwierzytelnianie nie powiedzie się, możemy uzupełnić właściwość errorMessage bardziej szczegółowym opisem przyczyny niepowodzenia.

Czy użytkownik został uwierzytelniony czy też nie, można sprawdzić w całej aplikacji poprzez użycie Yii::app()->user->isGuest. Jeśli używamy nośników trwałych danych takich jak sesja (domyślnie) i/lub ciasteczek (omówionych później) w celu zapisania informacji o tożsamości, użytkownik może pozostać zalogowany podczas kolejnych żądań. W tym przypadku, gdy nie potrzebujemy klasy UserIdentity oraz całego procesu logowania podczas każdege żądania. Raczej to CWebUser automatycznie zadba o ładowanie informacji o tożsamości użytkownika z nośnika trwałych danych i będzie używał ich do zdeterminowania czy Yii::app()->user->isGuest zwraca prawdę lub fałsz.

3. Logowanie przy użyciu ciasteczek

Domyślnie, użytkownik będzie wylogowany po pewnym czasie braku aktywności, w zależności od konfiguracji sesji. Aby zmienić to zachowanie, możemy ustawić właściwość komponentu użytkownika allowAutoLogin jako true oraz przekazać parametr określający okres trwania (ang. duration) do metody CWebUser::login. Użytkownik pozostanie zalogowany w podanym okresie, nawet jeśli zamknie okno swojej przeglądarki. Pamiętaj, że funkcjonalność ta wymaga aby przeglądarka użytkownika akceptowała ciasteczka.

// Utrzymaj użytkownika zalogowanym przez 7 dni
// upewnij się, że allowAutoLogin jest ustawiona jako true dla komponentu użytkownika
Yii::app()->user->login($identity,3600*24*7);

Jak wspomnieliśmy powyżej, kiedy logowanie za pomocą ciasteczej jest udostępnione, stany zachowane przez CBaseUserIdentity::setState będą również zapisane w ciasteczkach Następnym razem, gdy użytkownik zaloguje się, stany te będą odczytane z ciasteczek i staną się dostępne poprzez Yii::app()->user.

Chociaż Yii posiada środki do zabezpieczenia stanów w ciasteczkacj przez zmodyfikowaniem po stronie kienta, mocno rekomendujemy, by wrażliwe dane nie były przechowywane w stanach. Zamiast tego, informacje te powinny być odtwrzoene po stronie serwera poprzez odczytanie ich z jakiegoś nośnika danych trwałech po stronie serwera (np. z bazy danych).

Ponadto, w wielu poważnych aplikacjach sieciowych, zalecamy używanie następujacej strategii, w celu rozszerzenia bezpieczeństwa logowania przy użyciu cisteczek.

  • Jeśli użytkownik zaloguje się poprzez wypełnienie formualrza logowania, generujemy i zapisujemy losowy klucz zarówno w ciasteczku jak i w nośniku po stronie serwera (np. w bazie danych).

  • W kolejnych żądaniach, jeśli uwierzytelnianie poprzez ciasteczka zakończy się, porównujemy dwie kopie tych losowych kluczy i upewniamy się czy pasują one do siebie przed zalogowaniem użytkownika.

  • Jeśli użytkownik zaloguje się ponownie poprzez formularz logowania, klucz powinien zostać przegenerowany.

Używając powyższej strategii, wyeliminujemy możliwość ponownego użycia starego stanu z ciasteczek, które może posiadać przestarzałe informacje.

W celu zaimplementowanie powyższej strategii, musimy nadpisać następujące 2 metody:

  • CUserIdentity::authenticate(): to miejsce gdzie rzeczywiste uwierzytelnienie ma miejsce. Jeśli użytkownik jest uwierzytelniony, powinnniśmy przegenerować losowy klucz i zapisać go w bazie dancy tak jak i w stanie poprzez CBaseUserIdentity::setState.

  • CWebUser::beforeLogin(): metoda ta jest wołana gdy użytkownik loguje się. Powinniśmy sprawdzić jeśli klucz uzyskany ze stanu zapisanego w ciasteczku jest taki sam jak ten z bazy.

4. Filtr kontroli dostępu (ang. Access Control Filter)

Filtr kontroli dostępu jest wstępnym schematem autoryzacji, który sprawdza, czy aktualny użytkownik może wywoływać żądaną przez kontroler akcję. Autoryzacja bazuje na nazwie użytkownika, adresie IP klienta oraz type żądania. Jest ona dostarczona jako filtr nazwany "accessControl".

Porada: Filtr kontroli dostępu jest wystarczający dla prostych scenariuszy. Dla bardziej skomplikowanej kontroli dostępu możesz użyć bazującej na rolach kontroli dostępu (RBAC - role-based access control), która zostanie przedstawiona w dalszej części.

Aby kontrolować dostęp do akcji w kontrolerze instalujemy filtr kontroli akcji poprzez nadpisanie metody CController::filters (zobacz filtry aby uzyskać więcej informacji dotyczących instalowania filtrów).

class PostController extends CController
{
    ......
    public function filters()
    {
        return array(
            'accessControl',
        );
    }
}

Powyżej, określiliśmy, że filtr kontroli dostępu powinien być zastosowany dla każdej akcji kontrolera PostController. Szczegółowe reguły autoryzacji używane przez filtr są zdefiniowane poprzez nadpisanie CController::accessRules w klasie kontrolera.

class PostController extends CController
{
    ......
    public function accessRules()
    {
        return array(
            array('deny',
                'actions'=>array('create', 'edit'),
                'users'=>array('?'),
            ),
            array('allow',
                'actions'=>array('delete'),
                'roles'=>array('admin'),
            ),
            array('deny',
                'actions'=>array('delete'),
                'users'=>array('*'),
            ),
        );
    }
}

Powyższy kod definiuje 3 reguły, każda reprezentowana jest poprzez tablicę. Pierwszy element w tablicy to 'allow' (zezwól) lub 'deny' (zabroń) a pozostałe pary nazwa-wartość określają wzorce parametrów reguły. Reguły te odczytujemy następująco: akcje create (utwórz) oraz edit (redaguj) nie mogą być wykonywane przez anonimowych użytkowników; akcja delete (usuń) może zostać wykonywana przez użytkowników posiadających rolę admin; oraz akcja delete nie może być wykonywana przez wszystkich.

Reguły dostępu są sprawdzane jedna po drugiej w kolejności takiej w jakiej zostały wyspecyfikowane. Pierwsza reguła która pasuje do naszego wzorca (np. nazwa użytkownika, rola, IP klienta, adres) determinują rezultat autoryzacji. Jeśli regułą tą jest allow (zezwól) akcja może zostać wykonana; jeśli jest to reguła deny (zabroń), akcja nie może zostać wykonana; jeśli żadna z reguł nie pasuje do zawartości, akcja wciąż może być wykonana.

a matching-all deny rule at the end of rule set, like the following:

Wskazówka: Aby upewnić się, że akcja nie zostanie wykonana dla określonego kontekstu, najlepiej jest zawsze określić na końcu zbioru reguł, regułę, która będzie dotyczyła wszystkich i która zabroni dostępu do tej akcji, jak następuje:

return array(
    // ... pozostałe reguły ...
    // następująca reguła zabrania akcji 'delete' dla wszystkich kontekstów
    array('deny',
        'actions'=>'delete',
    ),
);

Powodem istnienia tej reguły jest fakt, że jeśli żadna z reguł nie będzie pasowała do kontekstu, akcja będzie kontynuować przetwarzanie.

Reguła dostępu może pasować do następujących parametrów kontekstowych:

  • actions: określa jakich akcji reguła ta dotyczy. Powinna być to tablica ID akcji. Porównywanie nie uwzględnia wielkości liter.

  • users: określa, których użytkowników reguła ta dotyczy. Aktualna nazwa użytkownika jest używana do sprawdzania. Porównywanie nie uwzględnia wielkości liter. Można tutaj używać 3 znaków specjalnych:

    • *: każdy użytkownik włączając w to użytkowników uwierzytelnionych jak i anonimowych,
    • ?: użytkownicy anonimowi,
    • @: użytkownicy uwierzytelnieni.
  • roles: określa, które role pasują do tych reguł. Używane w bazującej na rolach kontroli dostępu, która zostanie opisana w następnej podsekcji. W szczególności, reguła ma zastosowanie jeśli metoda CWebUser::checkAccess zwróci true dla jednej z ról. Zauważ, że powinieneś, głównie używać ról dla reguły allow (zezwól), ponieważ z definicji, rola reprezentuje pozwolenie na zrobienie czegoś. Należy również zauważyć, iż mimo tego, że używamy tutaj pojęcia role, ich wartości mogą być w rzeczywistości dowolnymi jednostkami autoryzacji włączając w to role, zadania oraz operacje.

  • ips: określa adres IP klienta dla pasującej reguły.

  • verbs: określa typ żądania (np.GET, POST) pasującej reguły. Porównywanie nie uwzględnia wielkości liter.

  • expression: określenia wyrażenie PHP, którego wartość określa czy reguła jest pasującą. W wyrażeniach możesz używać zmiennej użytkownika $user, która referuje do Yii::app()->user.

5. Zarządzanie wynikami autoryzacji

Kiedy autoryzacja nie powiedzie się, np. użytkownik nie może wykonać określonej akcji, jeden z dwóch poniższych scenariuszy może mieć miejsce:

  • jeśli użytkownik nie jest zalogowany i jeśli właściwość loginUrl komponentu użytkownika jest skonfigurowana jako URL strony logowania, przeglądarka zostanie przekierowana na tą stronę. Zauważ, że domyślnie loginUrl wskazuje na stronę site/login.

  • w przeciwnym przypadku wyjątek HTTP zostanie wyświetlony wraz z kodem błędu 403.

relatywny jak i absolutny URL. Można również przekazać tablicę, która będzie używana do wygenerowania URL poprzez wywołanie CWebApplication::createUrl. Pierwszy element tablicy powinien określać trasę do akcji logowania kontrolera a pozostałe pary parametrów nazwa-wartość są parametrami GET. Na przykład,

array(
    ......
    'components'=>array(
        'user'=>array(
          // to jest aktualna wartość domyślna
            'loginUrl'=>array('site/login'),
        ),
    ),
)

Jeśli przeglądarka zostanie przekierowana do strony logowania i logowanie zakończy się sukcesem, możemy chcieć aby przeglądarka została przekierowana z powrotem do strony, na której wystąpił błąd autoryzacji. Skąd znamy URL dla tej strony? Możemy otrzymać tą informację z właściwości returnUrl komponentu użytkownika. Możemy zrobić co następuje aby wykonać przekierowanie:

Yii::app()->request->redirect(Yii::app()->user->returnUrl);

6. Bazująca na rolach kontrola dostępu (ang. Role-Based Access Control)

Bazująca na rolach kontrola dostępu (RBAC) dostarcza prostej a zarazem potężnej, scentralizowanej kontroli dostępu. Zobacz artykuł wiki aby uzyskać więcej szczegółów dotyczących porównania RBAC z innymi, bardziej tradycyjnymi schematami kontroli dostępu.

Yii implementuje hierarchiczny schemat RBAC przy użyciu komponentu aplikacji authManager. W dalszej części, przedstawimy główne założenia używane w tym schemacie; później opiszemy jak zdefiniować dane autoryzacji; na końcu pokażemy jak użyć te dane aby wykonać sprawdzenie dostępu.

Przegląd

Podstawowym pojęciem w Yii RBAC jest jednostka autoryzacji (ang. authorization item). Jednostka autoryzacji jest przyzwoleniem na zrobienie czegoś (np. utworzenie nowego postu na blogu, zarządzania użytkownikami). W zależności od jej szczegółowości oraz grupy docelowej, jednostka autoryzacji może zostać sklasyfikowana jako operacje (ang. operations), zadania (ang. tasks) oraz role (ang. roles). Rola zawiera zadania, zadanie zawiera operacje a operacja jest pozwoleniem, które jest atomowe. Na przykład, możemy posiadać system w którym rola administratora administrator posiada zadanie zarządzania postami post management oraz zarządzania użytkownikami user management. Zadanie zarządzania użytkownikami user management może zawierać operacje utworzenia użytkownika create user, aktualizacji użytkownika update user oraz usunięcia użytkownika delete user. Dla uzyskania większej elastyczności, Yii pozwala również roli na posiadanie innych ról lub operacji, zadaniu na posiadanie innych zadań a operacji ma posiadanie innych operacji.

Jednostka autoryzacji jest jednoznacznie identyfikowana przez swoją nazwę.

Jednostka autoryzacji może być powiązana z regułą biznesową (ang. business rule). Rola biznesowa jest kawałkiem kodu PHP, który będzie wywołany, podczas sprawdzania dostępu na poziomie jednostki. Tylko wtedy gdy wywołanie zwróci true, użytkownikowi zostanie nadane uprawnienie reprezentowane przez jednostkę. Na przykład, kiedy definiujemy operację aktualizowania postu updatePost, chcielibyśmy dodać regułę biznesową, która sprawdza czy ID użytkownika jest identyczne z ID autora postu, tak że tylko autor sam będzie miał pozwolenie na aktualizację postu.

Używając jednostki autoryzacji możemy zbudować hierarchię autoryzacji (ang. authorization hierarchy). Jednostka A jest rodzicem innej jednostki B w hierarchii, jeśli A zawiera B (lub powiedzmy A dziedziny pozwolenie(a) reprezentowane przez B). Jednostka może posiadać wiele jednostek potomnych ale także może posiadać wiele jednostek rodziców. Dlatego też, hierarchia autoryzacji jest grafem częściowo-uporządkowanym a nie drzewem. W tej hierarchii jednostki ról znajdują się na najwyższych poziomach, jednostki operacji na dolnych poziomach, podczas gdy jednostki zadań znajdują się pomiędzy nimi.

Gdy już mamy hierarchię autoryzacji, możemy przypisać role w tej hierarchii do użytkowników aplikacji. Użytkownik raz przypisany do roli, będzie posiadał uprawnienia reprezentowane przez tą rolę. Na przykład, jeśli przypiszemy rolę administratora administrator do użytkownika, będzie on posiadał uprawnienia administratora, które zwierają zarządzanie postami post management oraz zarządzanie użytkownikami user management (oraz odpowiadające operacje, takie jak tworzenie użytkowników create user).

Teraz rozpoczyna się najzabawniejsza część. W akcji kontrolera, możemy sprawdzić, czy aktualny użytkownik może usunąć konkretny post. Używając hierarchii RBAC oraz przyporządkowań, można to zrobić prosto w następujący sposób:

if(Yii::app()->user->checkAccess('deletePost'))
{
    // usuń post
}

7. Konfigurowanie menadżera autoryzacji (ang. Configuring Authorization Manager)

Zanim zaczniemy definiować hierarchię autoryzacji oraz sprawdzać dostęp, musimy skonfigurować komponent aplikacji authManager. Yii dostarcza dwa typy menadżerów autoryzacji CPhpAuthManager oraz CDbAuthManager. Pierwszy używa pliku skryptu PHP do przechowywania danych autoryzacji, drugi zaś przechowuje dane autoryzacji w bazie. Gdy konfigurujemy komponent aplikacji authManager, musimy określić, którą klasę komponentu będziemy używać oraz jakie są inicjalne wartości właściwości dla tego komponentu. Na przykład,

return array(
    'components'=>array(
        'db'=>array(
            'class'=>'CDbConnection',
            'connectionString'=>'sqlite:path/to/file.db',
        ),
        'authManager'=>array(
            'class'=>'CDbAuthManager',
            'connectionID'=>'db',
        ),
    ),
);

Następnie możemy otrzymać dostęp do komponentu aplikacji authManager używając Yii::app()->authManager.

8. Definiowanie hierarchii autoryzacji (ang. Defining Authorization Hierarchy)

Definiowanie hierarchii auoryzacji składa się z 3 kroków: definiowania jednostek autoryzacji, ustalania relacji pomiędzy jednostkami autoryzacji oraz przypisywania ról do użytkowników aplikacji. Komponent aplikacji authManager dostarcza pełnego zestawu API do realizowania tych zadań.

Aby zdefiniować jednostkę autoryzacji, wywołaj jedną z poniższych metod w zależności od typu jednostki:

Gdy już mamy zestaw jednostek autoryzacji, możemy wywołać następujące metody aby ustalić relacje pomiędzy jednostkami:

Na koniec, możemy wywołać następujące metody aby powiązać jednostki ról z indywidualnymi użytkownikami:

Poniżej pokazujemy przykład jak zbudować hierarchię autoryzacji za pomocą dostarczonego API:

$auth=Yii::app()->authManager;
 
$auth->createOperation('createPost','tworzenie postu');
$auth->createOperation('readPost','czytanie postu');
$auth->createOperation('updatePost','aktualizowanie postu');
$auth->createOperation('deletePost','usuwanie postu');
 
$bizRule='return Yii::app()->user->id==$params["post"]->authID;';
$task=$auth->createTask('updateOwnPost','aktualizowanie postu przez autora',$bizRule);
$task->addChild('updatePost');
 
$role=$auth->createRole('reader');
$role->addChild('readPost');
 
$role=$auth->createRole('author');
$role->addChild('reader');
$role->addChild('createPost');
$role->addChild('updateOwnPost');
 
$role=$auth->createRole('editor');
$role->addChild('reader');
$role->addChild('updatePost');
 
$role=$auth->createRole('admin');
$role->addChild('editor');
$role->addChild('author');
$role->addChild('deletePost');
 
$auth->assign('reader','readerA');
$auth->assign('author','authorB');
$auth->assign('editor','editorC');
$auth->assign('admin','adminD');

Gdy już raz ustaliliśmy hierarchi, komponent authManager (np. CPhpAuthManager, CDbAuthManager) załaduje automatycznie pozycje. Dlatego też potrzebujemy wywołać powyższy kod jedynie raz, a NIE dla każdego żądania.

Info: Chociaż powyższy przykad wygląda przydługo oraz nużąco, należy pamiętać, że został on stworzony głównie w celach demonstracyjnych. Deweloperzy zazwyczaj będą potrzebowali wykonać pewne interfejsy użytkownika, tak, że użytkownicy końcowi, mogą ich uzywać do tworzenia hierarchii autoryzacji w sposób bardziej intuicyjny.

9. Używanie reguł biznesowych

Podczas definiowania hierarchii autoryzacji, możemy powiązać rolę, zadanie lub operację z tak zwaną reguły biznesowej (ang. business rule). Możemy również powiązać regułę biznesową podczas przypisywania roli do użytkownika. Reguła biznesowa jest fragmentem kodu PHP, który jest wykonywany podczas sprawdzania dostępności. Zwracana przez kod wartość jest używana do określenia, czy rola lub przypisanie ma zastosowanie dla aktualnego użytkownika. W powyższym przykładzie, powiązaliśmy regułe bizesową z zadaniem updateOwnPost task. W regule biznesowej po prostu sprawdzamy czy ID aktualnego użytkownika jest identyczne jak to określone przez ID autora postu. Informacja o poście w ablicy $params jest dostarczana przez programistę podczas sprawdzania dostępności.

Sprawdzanie dostępności

Aby dokonać sprawdzania dostępności, najpierw musimy znać nazwę jednostki autoryzacji. Na przykład, aby sprawdzić czy aktualny użytkonik może stworzyć post, musimy sprawdzić czy posiada on uprawnienie reprezentowane przez operację createPost. Wywołujemy wtedy metodę CWebUser::checkAccess aby wykonać sprawdzenie dostępności:

if(Yii::app()->user->checkAccess('createPost'))
{
    // utwórz post
}

Jeśli jednostka autoryzacji jest powiązana z reguła biznesową, która potrzebuje dodatkowwch parametrów, możemy je również przekazać. Na przykład, aby sprawdzić czy użytkownik może zaktualizwać post, przekażamy dane wiadomości poprzez zmienną $params:

$params=array('post'=>$post);
if(Yii::app()->user->checkAccess('updateOwnPost',$params))
{
    // zaktualizuj post
}

Używanie domyślnych ról

Wiele aplikacji webowych potrzebuje pewnych bardzo specjalnych ról, które będą przypisane do każdego lub prawie każdego użytkownika systemu. Na przykład, możemy chcież przypisać pewne uprawnienia do wszystkich uwierzytelnionych użytkowników. Powoduje to wiele kłopotów z zarządzaniem jeśli bezpośrednio wyspecyfikujemy i zachowamy przypisanie tych ról. Możemy wykorzystać domyślne role (ang. default roles) aby rozwiązać ten problem.

Rola domyślna jest rolą, która jest pośrednio przypisana do każdego użytkownika, wliczając w to uwierzytelnionego użytkownika a także gościa. Nie musimy jej bezpośrednio przypisywać do użytkownika. Kiedy wywołujemy CWebUser::checkAccess domyślne role będą sprawdzone najpierw jeśli są one przypisane do użytkownika.

Domyślne role muszą zostać zadeklarowane we właściwości CAuthManager::defaultRoles. Na przykład, następująca konfiguracja deklaruje dwie role, które będą domyślnymi: authenticated (uwierzytelniony) oraz guest (gość).

return array(
    'components'=>array(
        'authManager'=>array(
            'class'=>'CDbAuthManager',
            'defaultRoles'=>array('authenticated', 'guest'),
        ),
    ),
);

Ponieważ domyślan rola jest przypisywana do każdego użytkownika, zazwyczaj wymagane jest powiązanie z regułą biznesową, która determinuje czu rola naprawdę na zastosowanie dla użytkownika. Na przykład, następujący kod definiuje dwie role authenticated oraz guest, które efektywnie mają zastosowanie dla uwierzytelnionych użytkowników oraz gości, odpowiednio:

$bizRule='return !Yii::app()->user->isGuest;';
$auth->createRole('authenticated','uwierzytelniony użytkownik', $bizRule);
 
$bizRule='return Yii::app()->user->isGuest;';
$auth->createRole('guest','gość', $bizRule);
$Id: topics.auth.txt 2890 2011-01-18 15:58:34Z qiang.xue $

Be the first person to leave a comment

Please to leave your comment.