mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-10 18:16:53 +01:00
685 lines
28 KiB
Plaintext
685 lines
28 KiB
Plaintext
Authentifizierung und Autorisierung
|
|
===================================
|
|
|
|
Diese beiden Themen spielen dann eine Rolle, wenn einige Webseiten nur für
|
|
bestimmte Benutzer zugänglich sein sollen. Bei der *Authentifizierung* wird
|
|
geprüft, ob jemand auch tatsächlich der ist, der er vorgibt zu sein. Meist
|
|
geschieht das per Benutzernamen und Passwort. Man könnte aber auch eine andere
|
|
zur Identifizierung geeignete Methode verwenden, z.B. eine Chipkarte,
|
|
den Fingerabdruck, etc. Über die *Autorisierung* wird festgestellt, ob die
|
|
identifizierte (also authentifizierte) Person auch tatsächlich berechtigt
|
|
ist, bestimmte Ressourcen zu manipulieren. Normalerweise wird dazu geprüft, ob die
|
|
Person einer bestimmten Rolle zugeordnet ist, die Zugriff auf die Ressource
|
|
hat.
|
|
|
|
Yii hat ein einfach anzuwendendes Authentifizierungs-/Autorisierungs-Framework
|
|
(Auth-Framework) eingebaut, das leicht an spezielle Bedürfnisse angepasst werden kann.
|
|
|
|
Zentraler Bestandteil dieses Frameworks ist eine in der Anwendung
|
|
vordefinierte *Userkomponente* (Benutzerkomponente), die
|
|
das [IWebUser]-Interface implementiert. Diese Userkomponente stellt die
|
|
beständigen Identitätsdaten des aktuellen Benutzers dar.
|
|
Über `Yii::app()->user` kann von jeder Stelle aus darauf zugegriffen werden.
|
|
|
|
Mittels der Userkomponente kann man über [CWebUser::isGuest] prüfen,
|
|
ob ein Benutzer angemeldet ist oder nicht. Man kann einen Benutzer mit
|
|
[login|CWebUser::login] und [logout|CWebUser::logout] an- bzw. abmelden oder
|
|
mit [CWebUser::checkAccess] prüfen, ob der Benutzer bestimmte
|
|
Operationen ausführen kann. Außerdem kann man den [eindeutigen
|
|
Namen|CWebUser::name] bzw. auch andere beständige Identitätsdaten des
|
|
Benutzers abfragen.
|
|
|
|
|
|
Definieren der Identitätsklasse
|
|
-------------------------------
|
|
|
|
Wie bereits erwähnt, geht es bei der Authentifizierung darum, die Identität
|
|
eines Benutzers zu prüfen. Bei einer typischen Webanwendung werden dazu meist
|
|
ein Benutzername und ein Passwort herangezogen. Es kann aber auch andere
|
|
Methoden geben, die entsprechend eine andere Implementierung erfordern. Damit
|
|
die Art der Authentifizierung geändert werden kann, führt das
|
|
Yii Auth-Framework eine Identitätsklasse (engl.: identity class) ein.
|
|
|
|
Eine Identitätsklasse enthält die eigentliche Logik zur Authentifizierung und
|
|
sollte das [IUserIdentity]-Interface implementieren. So können Klassen für
|
|
verschiedene Identifizierungsmethoden (z.B. OpenID, LDAP, Twitter
|
|
OAuth oder Facebook Connect) angelegt werden. Um eine eigene Identitätsklasse
|
|
zu erstellen, empfiehlt es sich für den Anfang, [CUserIdentity] zu erweitern.
|
|
Das ist die Basisklasse für alle Methoden, die auf Benutzername und Passwort
|
|
basieren.
|
|
|
|
Im wesentlichen muss eine neue Identitätsklasse nur die Methode
|
|
[IUserIdentity::authenticate] implementieren. Sie kapselt die Kernlogik
|
|
zur Authentifizierung. Daneben können noch weitere identitätsbezogene Daten
|
|
deklariert werden, die während einer Benutzersitzung beständig bereitgehalten
|
|
werden sollen.
|
|
|
|
#### Ein Beispiel
|
|
|
|
Im folgenden Beispiel zeigen wir, wie man eine Identitätsklasse zur
|
|
datenbankgestützten Authentifizierung verwendet. Ein Besucher wird dazu
|
|
Benutzernamen und Passwort in ein Anmeldeformular eingeben. Diese Daten werden
|
|
dann mittels [ActiveRecord](/doc/guide/database.ar) gegen eine Benutzertabelle
|
|
in der Datenbank geprüft. Das Beispiel demonstriert dabei gleich mehreres:
|
|
|
|
1. Wie man `authenticate()` für eine DB-gestützte Prüfung der Anmeldedaten implementiert.
|
|
2. Dass man die `CUserIdentity::getId()`-Methode überschreiben kann, um die Eigenschaft `_id` statt des Benutzernamens zurückzuliefern, wie das in der Basisimplementierung der Fall ist.
|
|
3. Wie man die Methode `setState()` ([CBaseUserIdentity::setState]) verwendet, um weitere Daten dauerhaft für spätere Requests zu speichern
|
|
|
|
~~~
|
|
[php]
|
|
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;
|
|
}
|
|
}
|
|
~~~
|
|
|
|
Im nächsten Abschnitt zu An- und Abmeldung werden wir sehen, dass diese
|
|
Identitätsklasse an die login-Methode des Benutzerobjekts übergeben wird.
|
|
Sämtliche Informationen, die (per Aufruf von [CBaseUserIdentity::setState]) in
|
|
einem Status gespeichert wurden, werden dort in einem beständigen
|
|
Speicher, wie etwa der Session, abgelegt. Diese Daten stehen dann direkt als
|
|
Eigenschaften von [CWebUser] zur Verfügung. In unserem Beispiel haben wir den
|
|
Titel über `$this->setState('title', $record->title);` gespeichert. Wurde der
|
|
Anmeldeprozess durchlaufen, kann man daher die `title`-Information des aktuellen
|
|
Benutzers über `Yii::app()->user->title` abrufen. (Dies ist seit Version 1.0.3
|
|
möglich. In früheren Versionen musste man stattdessen
|
|
`Yii::app()->user->getState('title')` verwenden.)
|
|
|
|
> Info|Info: Standardmäßig verwendet [CWebUser] die Session als beständigen
|
|
Speicher für solche Identitätsdaten. Wenn die cookie-basierte Anmeldung aktiviert
|
|
wird (indem [CWebUser::allowAutoLogin] auf true gesetzt wurde), können
|
|
Identitätsdaten auch in einem Cookie gespeichert werden. Stellen Sie sicher,
|
|
dass Sie hier keine vertraulichen Informationen (z.B. Passwörter) speichern.
|
|
|
|
|
|
An- und Abmelden
|
|
----------------
|
|
|
|
Nachdem wir an einem Beispiel demonstriert haben, wie eine Identitätsklasse
|
|
erstellt wird, kann man diese nun zum einfachen An- und Abmelden verwenden.
|
|
Das folgende Beispiel zeigt, wie dies erreicht wird:
|
|
|
|
~~~
|
|
[php]
|
|
// Benutzer mit übergebenem Benutzernamen/Passwort anmelden
|
|
$identity=new UserIdentity($username,$password);
|
|
if($identity->authenticate())
|
|
Yii::app()->user->login($identity);
|
|
else
|
|
echo $identity->errorMessage;
|
|
......
|
|
// Aktuellen Benutzer abmelden
|
|
Yii::app()->user->logout();
|
|
~~~
|
|
|
|
Wir erzeugen hier eine neues UserIdentity-Objekt und übergeben die
|
|
Anmeldedaten (also die `$username`- und `$password`-Werte aus dem
|
|
Anmeldeformular) an den Konstruktor. Danach rufen wir einfach die
|
|
`authenticate()`-Methode auf. Falls erfolgreich, übergeben wir die
|
|
Identitätsinformationen an die Methode [CWebUser::login], die diese dann in
|
|
einem Permanentspeicher (standardmäßig der Sesssion) ablegt, um sie für
|
|
späteren Requests verfügbar zu machen. Schlägt die Authentifizierung fehl,
|
|
können wir über die `errorMessage`-Eigenschaft weitere Informationen dazu
|
|
abfragen.
|
|
|
|
Ob ein Benutzer erfolgreich authentifiziert wurde, kann in der gesamten
|
|
Anwendung einfach über `Yii::app()->user->isGuest` geprüft werden. Verwendet
|
|
man einen Permanentspeicher, wie die Session (Standard) und/oder ein Cookie
|
|
(wie im folgenden Beschrieben), um die Identitätsinformationen zu speichern,
|
|
kann der Anwender über mehrere aufeinanderfolgende Requests angemeldet
|
|
bleiben. In diesem Fall wird die Identitätsklasse bzw. der gesamte
|
|
Anmeldeprozess nicht bei jedem Request benötigt bzw. durchlaufen. Stattdessen
|
|
lädt CWebUser die Identitätsinformationen automatisch aus dem entsprechenden
|
|
Permanentspeicher und verwendet sie um den Rückgabewert von
|
|
`Yii::app()->user->isGuest` zu bestimmen.
|
|
|
|
|
|
Cookie-basierte Anmdeldung
|
|
--------------------------
|
|
|
|
Ein Benutzer wird automatisch wieder abgemeldet, wenn er für einen bestimmten
|
|
Zeitraum nicht aktiv war. Die Dauer hängt von der
|
|
[Session-Konfiguration](http://de2.php.net/manual/de/session.configuration.php)
|
|
ab. Möchte man das ändern, kann man die Eigenschaft
|
|
[allowAutoLogin|CWebUser::allowAutoLogin] der Userkomponente auf true setzen
|
|
und eine Dauer als zweiten Parameter an die [CWebUser::login]-Methode übergeben. Der
|
|
Benutzer bleibt dann für die angegebene Zeit angemeldet, auch wenn das
|
|
Browserfenster geschlossen wird. Beachten Sie, dass der Benutzer dazu in
|
|
seinem Browser Cookies akzeptieren muss.
|
|
|
|
~~~
|
|
[php]
|
|
// Benutzer für 7 Tage angemeldet lassen. Stellen Sie sicher,
|
|
// dass allowAutoLogin in der Userkomponente auf true gesetzt ist
|
|
Yii::app()->user->login($identity,3600*24*7);
|
|
~~~
|
|
|
|
Wie bereits erwähnt, werden Daten, die man über [CBaseUserIdentity::setState]
|
|
speichert, ebenfalls im Cookie abgelegt, falls man die cookie-basierte
|
|
Anmeldung verwendet. Wenn der Besucher das nächste mal angemeldet wird, werden
|
|
diese Daten aus dem Cookie ausgelesen und im Status über `Yii::app()->user`
|
|
bereitgestellt.
|
|
|
|
Auch wenn Yii Maßnahmen bereitstellt, um eine Veränderung dieser Cookiedaten
|
|
auf der Clientseite zu verhindern, empfehlen wir unbedingt, keine sensiblen
|
|
Daten als Status zu speichern. Stattdessen sollte man solche Daten auf der
|
|
Serverseite in einem Permanentspeicher (z.B. einer Datenbank) ablegen und bei
|
|
Bedarf wiederherstellen.
|
|
|
|
Für jede seriöse Webanwendung empfehlen wir außerdem folgende Strategie, um
|
|
die Sicherheit bei cookie-basierter Anmeldung zu verbessern:
|
|
|
|
* Zum Zeitpunkt, wenn ein Benutzer sich erfolgreich anmeldet, erzeugt man
|
|
einen zufälligen Schlüssel, der sowohl im Statuscookie als auch im
|
|
Permanentspeicher (z.B. Datenbank) auf dem Server gespeichert wird.
|
|
|
|
* Wenn der Benutzer bei einem späteren Request per Cookie angemeldet wird, überprüft man, ob die
|
|
beiden Schlüsselwerte übereinstimmen, bevor die Anmeldung durchgeführt wird.
|
|
|
|
* Wenn der Benutzer sich neu über das Anmeldeformular einloggt, muss ein neuer
|
|
Schlüssel erzeugt werden
|
|
|
|
Damit schließt man aus, dass der Besucher ein altes Statuscookie wiederverwendet,
|
|
dessen Statusinformationen aber schon nicht mehr gültig sind.
|
|
|
|
Zur Umsetzung dieser Strategie müssen folgende beiden Methoden überschrieben
|
|
werden:
|
|
|
|
* [CUserIdentity::authenticate()]: Hier wird die eigentliche Authentifizierung
|
|
durchgeführt. Wurde der Benutzer authentifiziert, sollte man hier einen neuen
|
|
Zufallsschlüssel erzeugen und diesen sowohl in der Datenbank als auch im
|
|
Identitätstatus (mit [CBaseUserIdentity::setState]) speichern.
|
|
|
|
* [CWebUser::beforeLogin()]: Diese Methode wird beim Anmelden eines
|
|
Benutzers aufgerufen. Hier sollte man den Schlüssel aus dem Statuscookie mit
|
|
dem in der Datenbank vergleichen.
|
|
|
|
Zugangskontrollfilter
|
|
---------------------
|
|
|
|
Mit dem Zugangskontrollfilter (engl.: access control filter) lässt sich prüfen,
|
|
ob der aktuelle Benutzer die gewünschte Controlleraction ausführen darf. Die
|
|
Prüfung erfolgt anhand des Benutzernamens, der IP-Adresse des Clients und dem
|
|
Requesttyp. Dieser einfache Filter steht als Anwendungskomponente
|
|
["accessControl"|CController::filterAccessControl] bereit.
|
|
|
|
> Tip|Tipp: Der Zugangskontrollfilter ist für einfache Fälle gedacht.
|
|
Kompliziertere Berechtigungsregeln kann man mit der rollenbasierten
|
|
Zugriffskontrolle (RBAC) umsetzen, die wir im nächsten Abschnitt
|
|
behandeln werden.
|
|
|
|
Um diesen Filter in einem Controller zu verwenden, überschreibt man die
|
|
[CController::filters]-Methode wie folgt (siehe auch
|
|
[Filter](/doc/guide/basics.controller#filter) zu näheren Details über
|
|
die Anwendung von Filtern):
|
|
|
|
~~~
|
|
[php]
|
|
class PostController extends CController
|
|
{
|
|
......
|
|
public function filters()
|
|
{
|
|
return array(
|
|
'accessControl',
|
|
);
|
|
}
|
|
}
|
|
~~~
|
|
|
|
Mit dieser Funktion legt man fest, dass der
|
|
[Zugangskontrollfilter|CController::filterAccessControl] auf alle Actions des
|
|
`PostController`s angewendet werden soll. Die spezifischen Berechtigungen
|
|
werden in der Methode [CController::accessRules] angegeben, die man z.B. so
|
|
überschreiben kann:
|
|
|
|
~~~
|
|
[php]
|
|
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('*'),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
~~~
|
|
|
|
Hier werden drei Regeln in jeweils einem Array definiert. Das erste Element
|
|
eines solchen Arrays ist entweder `'allow'` (erlaube) oder `'deny'` (verbiete). Die
|
|
weiteren Name-Wert-Paare bestimmen, wann diese Regel gilt. Die Regeln
|
|
oben bedeuten der Reihe nach, dass die `create`- und `edit`-Actions nicht von
|
|
anonymen Benutzern aufgerufen werden können. Die `delete`-Action darf von Benutzern
|
|
mit der Rolle `admin` ausgeführt werden. Und die `delete`-Action darf von
|
|
keinem Benutzer ausgeführt werden.
|
|
|
|
Die Zugriffsregeln werden eine nach der anderen in der Reihenfolge ihrer
|
|
Definition geprüft. Die erste Regel, die vollständig auf den aktuellen
|
|
Kontext (z.B. Benutzername, Rolle, IP-Adresse) zutrifft, bestimmt das
|
|
Ergebnis. Falls es sich um eine `allow`-Regel handelt, darf die
|
|
Action ausgeführt werden, liegt eine `deny`-Regel vor, darf sie nicht
|
|
ausgeführt werden. Passt keine der definierten Regeln auf den aktuellen
|
|
Kontext, darf die Action ausgeführt werden.
|
|
|
|
> Tip|Tipp: Um sicherzustellen, dass eine Action nicht doch unter einem bestimmten
|
|
> Kontext ausgeführt werden kann, ist es hilfreich, eine immergültige
|
|
> `deny`-Regel ans Ende seiner Regeln zu setzen:
|
|
> ~~~
|
|
> [php]
|
|
> return array(
|
|
> // ... Andere Regeln ...
|
|
> // Die folgende Regel verbietet die 'delete'-Action in jedem Kontext
|
|
> array('deny',
|
|
> 'actions'=>array('delete'),
|
|
> ),
|
|
> );
|
|
> ~~~
|
|
> Diese Regel ist nötig, da eine Action ausgeführt werden darf, falls keine
|
|
> anderslautende passende Regel gefunden wurde.
|
|
|
|
Eine Regel kann folgende Kontextparameter enthalten:
|
|
|
|
- [actions|CAccessRule::actions]: Definiert, welche Actions diese Regel
|
|
betrifft. Dies sollte ein Array aus Action-IDs sein, Groß-/Kleinschreibung
|
|
spielt hierbei keine Rolle.
|
|
|
|
- [controllers|CAccessRule::controllers]: Definiert, welche Controller
|
|
diese Regel betrifft. Dies sollte ein Array aus Controller-IDs sein,
|
|
Groß-/Kleinschreibung spielt hierbei keine Rolle. Diese Option ist seit
|
|
Version 1.0.4 verfügbar.
|
|
|
|
- [users|CAccessRule::users]: Definiert, welche Benutzer diese Regel
|
|
betrifft. Zur Prüfung wird der [Name|CWebUser::name] des aktuellen Benutzers
|
|
herangezogen, Groß-/Kleinschreibung spielt hierbei keine Rolle.
|
|
Hier können drei spezielle Zeichen verwendet werden:
|
|
|
|
- `*`: Jeder Benutzer, inkl. anonyme und authentifizierte Benutzer.
|
|
- `?`: Anonyme (nicht angemeldete) Benutzer.
|
|
- `@`: Authentifizierte (angemeldete) Benutzer.
|
|
|
|
- [roles|CAccessRule::roles]: Definiert, welche Rollen diese Regel
|
|
betrifft. Dazu wird die [rollenbasierte
|
|
Zugriffskontrolle](/doc/guide/topics.auth#role-based-access-control) verwendet, die wir im nächsten
|
|
Abschnitt beschreiben werden. Konkret wird diese Regel angewendet, wenn
|
|
[CWebUser::checkAccess] für eine der Rollen true zurückliefert. Beachten Sie,
|
|
dass Sie Rollen vor allem in `allow`-Regeln einsetzen sollten, da eine Rolle
|
|
per Definition eine Erlaubnis darstellt, etwas bestimmtes zu tun. Und obwohl
|
|
wir hier den Begriff `roles` (Rollen) verwenden, kann der Wert tatsächlich
|
|
jedem beliebigen Autorisierungselement entsprechen, inklusive Rollen, Tätigkeiten und
|
|
Operationen.
|
|
|
|
- [ips|CAccessRule::ips]: Definiert, welche Client-IP-Adressen diese
|
|
Regel betrifft.
|
|
|
|
- [verbs|CAccessRule::verbs]: Definiert, welche Requesttypen (z.B. 'GET',
|
|
'POST') diese Regel betrifft. Groß-/Kleinschreibung spielt hierbei keine
|
|
Rolle.
|
|
|
|
- [expression|CAccessRule::expression]: Definiert einen PHP-Ausdruck,
|
|
dessen Wert darüber entscheidet, ob die Regel zutrifft oder nicht. Im Ausdruck
|
|
können Sie `$user` für `Yii::app()->user` verwenden. Diese Option ist seit
|
|
Version 1.0.3 verfügbar.
|
|
|
|
|
|
Verhalten nach der Autorisierung
|
|
--------------------------------
|
|
|
|
Wurde eine Autorisierung verweigert, so ist der Benutzer nicht berechtigt,
|
|
die gewünschte Action auszuführen und es passiert folgendes:
|
|
|
|
- War der Benutzer nicht angemeldet und zeigt die Eigenschaft
|
|
[loginUrl|CWebUser::loginUrl] der Userkomponente auf die URL der Anmeldeseite,
|
|
so wird der Browser auf diese Seite umgeleitet. Beachten Sie, dass
|
|
[loginUrl|CWebUser::loginUrl] standardmäßig auf die Seite `site/login` zeigt.
|
|
|
|
- In allen anderen Fällen wird eine HTTP-Exception mit dem Fehlercode 403 angezeigt.
|
|
|
|
[loginUrl|CWebUser::loginUrl] kann als relative oder absolute URL angegeben werden.
|
|
Man kann auch ein Array konfigurieren, das dann an [CWebApplication::createUrl]
|
|
übergeben wird, um damit eine URL zu erzeugen.
|
|
Das erste Element dieses Arrays sollte die [Route](/doc/guide/basics.controller#route)
|
|
zur Anmeldeaction angeben. Der Rest kann aus Name-Wert-Paaren für GET-Parameter bestehen.
|
|
Hier ein Beispiel:
|
|
|
|
~~~
|
|
[php]
|
|
array(
|
|
......
|
|
'components'=>array(
|
|
'user'=>array(
|
|
// Dies entspricht dem Vorgabewert
|
|
'loginUrl'=>array('site/login'),
|
|
),
|
|
),
|
|
)
|
|
~~~
|
|
|
|
Wurde der Browser auf die Anmeldeseite umgeleitet und verläuft die Anmeldung
|
|
erfolgreich, kann man den Browser zurück zu der Seite schicken, bei der
|
|
die Autorisierung verweigert wurde. Die URL dieser Seite kann über die Eigenschaft
|
|
[returnUrl|CWebUser::returnUrl] der Userkomponente abgerufen werden:
|
|
|
|
~~~
|
|
[php]
|
|
Yii::app()->request->redirect(Yii::app()->user->returnUrl);
|
|
~~~
|
|
|
|
Rollenbasierte Zugriffskontrolle
|
|
--------------------------------
|
|
|
|
Die rollenbasierte Zugriffskontrolle (RBAC, engl.: role-based access control)
|
|
bietet eine einfache und trotzdem leistungsfähige zentralisierte
|
|
Zugriffssteuerung. Für weitere Ausführungen zum Vergleich von RBAC mit anderen
|
|
traditionellen Verfahren der Berechtigungsprüfung beachten Sie bitte auch den
|
|
entsprechenden [Wiki-Artikel](http://de.wikipedia.org/wiki/RBAC) (evtl. auch
|
|
in der ausührlicheren [englischen
|
|
Version](http://en.wikipedia.org/wiki/Role-based_access_control)).
|
|
|
|
Yii implementiert über seine
|
|
[authManager|CWebApplication::authManager]-Komponente ein hierarchisches
|
|
RBAC-Schema. Im folgenden behandeln wir zunächst die Grundkonzepte dieses
|
|
Schemas. Danach beschreiben wir, wie man Autorisierungsdaten definiert und
|
|
schließlich wie man diese für die Berechtigungsprüfung verwendet.
|
|
|
|
### Übersicht
|
|
|
|
Einer der grundlegenden Begriffe bei RBAC mit Yii ist das
|
|
*Autorisierungselement* (engl.: authorization item). Ein Autorisierungselement
|
|
steht für die Erlaubnis, etwas bestimmtes zu tun (z.B. einen Blogeintrag anzulegen
|
|
oder Benutzer zu verwalten). Gemäß ihrer Beschaffenheit und dem anvisierten
|
|
Zielpublikum können Autorisierungselemente in *Operationen* (engl.:
|
|
operations), *Tätigkeiten* (engl.: tasks) und *Rollen* (engl.: roles) eingeteilt
|
|
werden. Eine Rolle besteht aus Tätigkeiten, eine Tätigkeit aus Operationen. Eine
|
|
Operation steht für eine atomare Berechtigung.
|
|
|
|
In einem System kann es zum Beispiel eine Rolle `administrator` geben. Sie
|
|
besteht aus den Tätigkeiten `Beiträge verwalten` und `Benutzer verwalten`.
|
|
Die Tätigkeit `Benutzer verwalten` könnte aus den Operationen
|
|
`Benutzer anlegen`, `Benutzer aktualisieren` und `Benutzer löschen` bestehen.
|
|
Um das System noch flexibler zu machen, erlaubt es Yii
|
|
sogar, dass eine Rolle aus weiteren Rollen oder Operationen, eine
|
|
Tätigkeit aus anderen Tätigkeiten und eine Operation aus anderen Operationen
|
|
besteht.
|
|
|
|
Ein Autorisierungselement wird eindeutig über seinen Namen identifiziert und
|
|
kann mit einer *Geschäftsregel* (engl.: business
|
|
rule) verbunden sein. Eine Geschäftsregel ist ein PHP-Schnippsel, das
|
|
ausgeführt wird, wenn die Berechtigung für das Element geprüft wird.
|
|
Liefert dieser Code true zurück, so ist der Benutzer zu diesem Element
|
|
berechtigt. Definiert man zum Beispiel eine Operation `aktualisiereBeitrag`,
|
|
kann man eine Geschäftsregel hinzufügen, die prüft, ob die ID des Benutzers
|
|
mit derjenigen des Beitragsautors übereinstimmt, so dass nur der Autor selbst
|
|
berechtigt ist, seine Beiträge zu aktualisieren.
|
|
|
|
Durch den Einsatz von Autorisierungselementen kann man eine
|
|
*Autorisierungshierarchie* aufbauen. Ein Element `A` ist das Elternelement
|
|
eines anderen Elements `B` in der Hierarchie, wenn `A` aus `B` besteht (oder
|
|
anders ausgedrückt `A` die von `B` dargestellten Berechtigung(en) erbt).
|
|
Ein Element kann sowohl mehrere Kind- als auch mehrere Elternelemente
|
|
haben. Eine Autorisierungshierarchie ist daher eher ein Graph partieller
|
|
Ordnung als eine Baumstruktur. In dieser Hierarchie stehen Rollen auf der
|
|
obersten Ebene, Operationen auf der untersten und Tätigkeiten zwischen diesen
|
|
beiden.
|
|
|
|
Wurde die Autorisierungshierarchie einmal erstellt, kann man Benutzer zu den
|
|
Rollen in dieser Hierarchie hinzufügen. Ein Benutzer, dem eine Rolle
|
|
zugewiesen wurde, hat alle von dieser Rolle dargestellten Berechtigungen. Weist man
|
|
einem Benutzer z.B. die Rolle `administrator` zu, hat er Administratorrechte,
|
|
was die Tätigkeiten `Beiträge verwalten` und `Benutzer verwalten` beinhaltet
|
|
(sowie die zugehörigen Operationen wie `Benutzer anlegen`).
|
|
|
|
Am einfachsten stellt sich die Anwendung dar: Möchte man in einer
|
|
Controlleraction prüfen, ob der aktuelle Benutzer den Beitrag
|
|
löschen kann, geht das so:
|
|
|
|
~~~
|
|
[php]
|
|
if(Yii::app()->user->checkAccess('löscheBeitrag'))
|
|
{
|
|
// Beitrag löschen
|
|
}
|
|
~~~
|
|
|
|
Konfigurieren des Autorisierungsmanagers
|
|
----------------------------------------
|
|
|
|
Bevor man eine Autorisierungshierarchie anlegen und den Zugriffsschutz
|
|
einsetzen kann, muss die [authManager|CWebApplication::authManager]-Komponente
|
|
konfiguriert werden. Yii bietet hier zwei Typen an: [CPhpAuthManager] und [CDbAuthManager].
|
|
Der erste speichert die Autorisierungsdaten in einer PHP-Datei, der andere
|
|
in der Datenbank. Über die Klasse kann man einen dieser Typen, sowie dessen
|
|
Starteigenschaften konfigurieren:
|
|
|
|
|
|
~~~
|
|
[php]
|
|
return array(
|
|
'components'=>array(
|
|
'db'=>array(
|
|
'class'=>'CDbConnection',
|
|
'connectionString'=>'sqlite:pfad/zu/datei.db',
|
|
),
|
|
'authManager'=>array(
|
|
'class'=>'CDbAuthManager',
|
|
'connectionID'=>'db',
|
|
),
|
|
),
|
|
);
|
|
~~~
|
|
|
|
Jetzt kann man über `Yii::app()->authManager` auf den
|
|
[authManager|CWebApplication::authManager] zugreifen.
|
|
|
|
> Note|Hinweis: Wenn Sie Umlaute für die Bezeichnung Ihrer
|
|
Autorisierungselemente verwenden möchten, achten Sie bitte darauf, dass sie
|
|
die entsprechenden Tabellen mit UTF-8-Codierung anlegen und sie bei der
|
|
Konfiguration der Datenbankverbindung die Eigenschaft
|
|
[CDbConnection::charset] ebenfalls auf `utf8` setzen.
|
|
|
|
Anlegen einer Autorisierungshierarchie
|
|
--------------------------------------
|
|
|
|
Das Anlegen einer Autorisierungshierarchie beinhaltet drei Schritte:
|
|
Autorisierungselemente anlegen, zwischen diesen Elementen Beziehungen
|
|
definieren und Benutzern Rollen zuweisen. Die
|
|
[authManager|CWebApplication::authManager]-Komponente bietet hierfür
|
|
eine ganze Reihe von APIs.
|
|
|
|
Rufen Sie je nach Art des Elements eine der folgenden Methoden auf, um ein
|
|
Autorisierungselement zu erstellen:
|
|
|
|
- [CAuthManager::createRole] (erzeugt Rolle)
|
|
- [CAuthManager::createTask] (erzeugt Tätigkeit)
|
|
- [CAuthManager::createOperation] (erzeugt Operation)
|
|
|
|
Hat man eine Reihe von Autorisierungselementen angelegt, kann man mit
|
|
den folgenden Methoden Beziehungen zwischen diesen Elementen definieren:
|
|
|
|
- [CAuthManager::addItemChild] (definiert Eltern-Kind-Beziehung)
|
|
- [CAuthManager::removeItemChild] (entfernt Eltern-Kind-Beziehung)
|
|
- [CAuthItem::addChild] (definiert Kind-Beziehung von Elternelement aus)
|
|
- [CAuthItem::removeChild] (entfernt Kind-Beziehung von Elternelement aus)
|
|
|
|
Um schließlich einzelnen Benutzern Rollen zuzuweisen, ruft man folgende Methoden
|
|
auf:
|
|
|
|
- [CAuthManager::assign] (weist Rolle zu)
|
|
- [CAuthManager::revoke] (entfernt zugewiesene Rolle)
|
|
|
|
Unten sehen Sie ein Beispiel, wie man mit dieser API eine
|
|
Autorisierungshierarchie aufbaut:
|
|
|
|
~~~
|
|
[php]
|
|
$auth=Yii::app()->authManager;
|
|
|
|
$auth->createOperation('erstelleBeitrag','Einen Beitrag erstellen');
|
|
$auth->createOperation('leseBeitrag','Einen Beitrag lesen');
|
|
$auth->createOperation('aktualisiereBeitrag','Einen Beitrag aktualisieren');
|
|
$auth->createOperation('löscheBeitrag','Einen Beitrag löschen');
|
|
|
|
$bizRule='return Yii::app()->user->id==$params["post"]->authID;';
|
|
$task=$auth->createTask('aktualisiereEigenenBeitrag','Einen eigenen Beitrag aktualisieren',$bizRule);
|
|
$task->addChild('aktualisiereBeitrag');
|
|
|
|
$role=$auth->createRole('leser');
|
|
$role->addChild('leseBeitrag');
|
|
|
|
$role=$auth->createRole('autor');
|
|
$role->addChild('leser');
|
|
$role->addChild('erstelleBeitrag');
|
|
$role->addChild('aktualisiereEigenenBeitrag');
|
|
|
|
$role=$auth->createRole('redakteur');
|
|
$role->addChild('leser');
|
|
$role->addChild('aktualisiereBeitrag');
|
|
|
|
$role=$auth->createRole('admin');
|
|
$role->addChild('redakteur');
|
|
$role->addChild('autor');
|
|
$role->addChild('löscheBeitrag');
|
|
|
|
$auth->assign('leser','leserA');
|
|
$auth->assign('autor','autorB');
|
|
$auth->assign('redakteur','redakteurC');
|
|
$auth->assign('admin','adminD');
|
|
~~~
|
|
|
|
Wurden diese Hierarchie einmalig erstellt, wird sie automatisch von der
|
|
[authManager|CWebApplication::authManager]-Komponente (also
|
|
z.B. [CPhpAuthManager] oder [CDbAuthManager]) geladen. Man muss obigen
|
|
Code also nur einmal ausführen, NICHT bei jeden Request.
|
|
|
|
> Info|Info: Das Verfahren oben mutet etwas umständlich an. Es soll
|
|
> aber lediglich das Prinzip demonstrieren. In der Regel wird der
|
|
> Entwickler eine geeignete Verwaltungsschnittstelle entwerfen, mit
|
|
> der man Autorisierungshierarchien intuitiver erstellen kann.
|
|
|
|
|
|
Anwendung von Geschäftsregeln
|
|
-----------------------------
|
|
|
|
Erstellt man eine Autorisierungshierarchie, kann man eine Rolle, eine
|
|
Tätigkeit oder eine Operation mit einer sogenannten *Geschäftsregel* versehen.
|
|
Auch beim Zuweisen einer Rolle an einen Benutzer kann man eine solche
|
|
Geschäftsregel angeben. Eine Geschäftsregel ist ein PHP-Schnippsel,
|
|
der während der Berechtigungsprüfung ausgeführt wird. In obigem Beispiel
|
|
wurde bei der Tätigkeit `aktualisiereEigenenBeitrag`
|
|
eine solche Geschäftsregel definiert. Darin wird einfach geprüft,
|
|
ob die ID des aktuellen Benutzers mit der des Autors übereinstimmt.
|
|
Bei der Zugriffsprüfung wird der Beitrag (post) vom
|
|
Entwickler im Array `$params` übergeben.
|
|
|
|
### Berechtigungsprüfung
|
|
|
|
Um die Berechtigungsprüfung durchzuführen, braucht man zunächst den Namen des
|
|
Autorisierungselements. Will man zum Beispiel zu testen, ob der aktuelle
|
|
Benutzer einen Beitrag erstellen kann, muss die Berechtigung zur Operation
|
|
`erstelleBeitrag` ermittelt werden. Dazu ruft man [CWebUser::checkAccess]
|
|
wie folgt auf:
|
|
|
|
~~~
|
|
[php]
|
|
if(Yii::app()->user->checkAccess('erstelleBeitrag'))
|
|
{
|
|
// Beitrag erstellen
|
|
}
|
|
~~~
|
|
|
|
Ist eine Geschäftsregel mit weiteren Parametern mit dem Element verbunden,
|
|
können diese ebenfalls mit übergeben werden. Um zum Beispiel zu prüfen, ob
|
|
ein Benutzer einen bestimmten Beitrag aktualisieren darf, würde man die
|
|
Beitragsdaten in `$params` übergeben:
|
|
|
|
~~~
|
|
[php]
|
|
$params=array('post'=>$post);
|
|
if(Yii::app()->user->checkAccess('aktualisiereEigenenBeitrag',$params))
|
|
{
|
|
// Beitrag aktualisieren
|
|
}
|
|
~~~
|
|
|
|
### Verwenden von Standardrollen
|
|
|
|
> Note|Hinweis: Standardrollen können seit Version 1.0.3 verwendet werden.
|
|
|
|
In vielen Webanwendungen gibt es einige Rollen, denen praktisch alle Benutzer
|
|
zugewiesen werden sollen, um z.B. alle authentifizierten Benutzer mit
|
|
bestimmten Basisberechtigungen zu versehen. Man könnte also diesen Rollen
|
|
jeden einzelnen Benutzer zuwiesen, was allerdings relativ hohen Verwaltungsaufwand
|
|
bedeutet. Stattdessen kann man aber auch *Standardrollen* (engl.: default roles) verwenden.
|
|
|
|
Eine Standardrolle ist eine Rolle, die implizit allen Benutzern zugewiesen
|
|
wird und zwar authentifizierten Benutzern genauso, wie Gästen. Man muss ihnen
|
|
nicht explizit Benutzer zuweisen. Beim Aufruf von
|
|
[CWebUser::checkAccess] werden zunächst die Standardrollen überprüft, als ob
|
|
sie dem Benutzer zugewiesen worden wären.
|
|
|
|
Standardrollen müssen in der Eigenschaft [CAuthManager::defaultRoles]
|
|
deklariert werden. Die folgende Konfiguration legt zum Beispiel zwei
|
|
Standardrollen fest: `authentifiziert` und `gast`.
|
|
|
|
~~~
|
|
[php]
|
|
return array(
|
|
'components'=>array(
|
|
'authManager'=>array(
|
|
'class'=>'CDbAuthManager',
|
|
'defaultRoles'=>array('authentifiziert', 'gast'),
|
|
),
|
|
),
|
|
);
|
|
~~~
|
|
|
|
Da eine Standardrolle jedem Benutzer zugewiesen wird, wird sie normalerweise
|
|
mit einer Geschäftsregel verbunden, um festzustellen, ob die Rolle
|
|
wirklich auf den Benutzer zutrifft. Der folgende Code definiert zum Beispiel
|
|
zwei Rollen, "authentifiziert" und "gast", die letzendlich authentifizierten
|
|
Benutzern und Gästen entsprechend zugeordnet werden.
|
|
|
|
~~~
|
|
[php]
|
|
$bizRule='return !Yii::app()->user->isGuest;';
|
|
$auth->createRole('authentifiziert','Autentifizierte Benutzer', $bizRule);
|
|
|
|
$bizRule='return Yii::app()->user->isGuest;';
|
|
$auth->createRole('gast','Gast-Benutzer', $bizRule);
|
|
~~~
|
|
|
|
<div class="revision">$Id: topics.auth.txt 2739 2010-12-14 01:50:04Z weizhuo $</div>
|