26.09.2008, 21:06
Für eine komplette Userauthentifizierung benötigen wir 4 Sachen :
Also erstmal legen wir einen neuen Ordner im Verzeichnis library an den ich hier MyWork nennen werde.
In diesem Ordner legen wir nun 3 Datein an :
Arbeiten wir uns nun mal von oben nach unten dutch die Datein.
Inhalt von myacl.php
[code=php]
<?php
class MyWork_myacl extends Zend_Acl
{
public function __construct(Zend_Auth $auth)
{
$this->add(new Zend_Acl_Resource('index'));
$this->addRole(new Zend_Acl_Role('gast'))
->addRole(new Zend_Acl_Role('admin'),'gast');
$this->allow('gast','index','index');
->allow('admin','index',array('neuenuser','userlöschen'));
}
}
[/code]
Die Klasse muss so benannt werden damit sie von Zend_Auoload im Unterordner gefunden wird ( wer sich also bis jetzt gewundert hat warum alle Zend Klassen mit dem Präfix 'Zend_' beginnen, dem geht jetzt wohl ein Licht auf
Was passiert in dieser Date ?
Erst definieren wir Resourcen. Wir können mit Zend_Acl nur den Zugriff von Usern auf Resourcen kontrollieren. Es macht daher sinn diese Resourcen sinnig zu bennenen. Ich benutze hier den Controllernamen.
Den Actionnamen sollten wir nicht nehmen, da man später die Action als zusätzlich behandeln kann.
Dann müssen wir Rollen ( Benutzergruppen ) anlegen.
Eine Rolle sollte immer 'gast' o.ä. heißen. Schließlich brauchen wir eine Klasse die alle nicht angemeldeten User bekommen.
Zusätzlich definiere ich nun noch eine Admingruppe.
Durch den 2. Parameter 'gast' lasse ich der Admingruppe alle Erlaubnisse von der Gruppe gast erben.
Also wenn Gast nun Zugriff auf xyz hat, dann hat die Admingruppe automatisch auch Zugriff auf jene Resource.
Als nächstes sagen wir der Klasse welche Usergruppen auf welche Resource Zugriff hat.
[code=php]allow('gast','index','index')[/code]
Gast hat nun Zugriff auf die Resource 'index' und dort auf die Action 'index'.
Admin hat nun automatisch durch die Vererbung auch Zugriff auf diese Action.
[code=php]allow('admin','index',array('neuenuser','userlöschen')[/code]
Admin hat nun Zugriff auf die Resource 'index' und dort auf die beiden Action´s 'neuenuser' und 'userlöschen'.
Inhalt von myauth.php
[code=php]
<?php
class MyWork_myauth extends Zend_Controller_Plugin_Abstract
{
private $_auth;
private $_acl;
private $_noauth = array('module' => 'default',
'controller' => 'user',
'action' => 'nouser');
private $_noacl = array('module' => 'default',
'controller' => 'error',
'action' => 'noaccess');
public function __construct($auth, $acl) {
$this->_auth = $auth;
$this->_acl = $acl;
}
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$controller = $request->getControllerName();
$action = $request->getActionName();
$module = $request->getModuleName();
$resource = $controller;
if ($this->_auth->hasIdentity()) {
$role = $this->_auth->getIdentity()->role;
} else {
$role = 'gast';
}
if (!$this->_acl->has($resource)) {
$resource = null;
}
if (!$this->_acl->isAllowed($role, $resource, $action)) {
if (!$this->_auth->hasIdentity()) {
$module = $this->_noauth['module'];
$controller = $this->_noauth['controller'];
$action = $this->_noauth['action'];
} else {
$module = $this->_noacl['module'];
$controller = $this->_noacl['controller'];
$action = $this->_noacl['action'];
}
}
$request->setModuleName($module);
$request->setControllerName($controller);
$request->setActionName($action);
}
}
[/code]
Was passiert in dieser Datei ?
Die ersten Zeilen sollten sich von selbst erklären . OOP in PHP möchte ich hier nicht näher erlätern.
Die Funktion preDispatch wird vor dem Abarbeiten des Controllers gestartet. Als parameter wird hier das Request-Objekt übergeben. Aus diesem können wir nun auslesen auf welche Seite der User gerade zugreifen möchte :
[code=php]
$controller = $request->getControllerName();
$action = $request->getActionName();
$module = $request->getModuleName();
[/code]
Nun müssen wir noch prüfen ob der User eingeloggt ist, und festlegen das unsere Resource aus Acl hier gleichzusetzten ist mit dem Controller, welcher aufgerufen werden soll.
[code=php]
$resource = $controller;
if ($this->_auth->hasIdentity()) {
$role = $this->_auth->getIdentity()->role;
} else {
$role = 'gast';
}
[/code]
Wenn der User nicht eingeloggt ist, so wird ihm die Rolle 'gast' gegeben.
Die wichtigsten Zeilen :
[code=php]
if (!$this->_acl->isAllowed($role, $resource, $action)) {
if (!$this->_auth->hasIdentity()) {
$module = $this->_noauth['module'];
$controller = $this->_noauth['controller'];
$action = $this->_noauth['action'];
} else {
$module = $this->_noacl['module'];
$controller = $this->_noacl['controller'];
$action = $this->_noacl['action'];
}
}
[/code]
Hier wird geprüft ob der User mit der Rolle $role auf die Resource $resource und dort auf die Action $action keinen Zugriff hat.
Wenn dies der Fall ist wird entschieden ob er auf die Loginseite weitergeleitet werden sollte, oder ob ihm eine Seite angezeigt werden soll, die ihm sagt, dass er keinen Zugriff auf diese Seite hat.
Schließlich werden noch die eventuell neuen Angaben an den Request weitergegeben.
So einfach ist der Hauptteil
Nun der Inhalt von myauthadapter.php
[code=php]
<?php
require_once 'Zend/Auth/Adapter/DbTable.php';
class MyWork_myauthadapter extends Zend_Auth_Adapter_DbTable
{
public $authAdapter;
public function __construct() {
$db = Zend_Registry::get('db');
parent::__construct($db);
$this->setTableName('tabelle_mit_userdaten');
$this->setIdentityColumn('spalte_mit_username');
/* Passwörter sollten verschlüsselt sein */
$this->setCredentialColumn('spalte_mit_passwort');
/* Falls verschlüsselt dann hier sagen wie */
$this->setCredentialTreatment('MD5(?)'');
}
}
[/code]
Es gibt auch andere Adapterklassen. Wer also nicht MySQL nutzt kann sich mal in dem Teil des Manuals umsehen [1]
So das wären auch schon alle wichtigen Sachen.
Als letztes noch das Loginformular. Wir bauen das Formular am besten so ein das in der selben Funktion auch der tatsächliche Loginvorgang abläuft.
[code=php]
// Klasse usw. hier erstellen
private function loginForm()
{
$login = new Zend_Form();
$login->setAction('/user/login')
->setMethod('post');
$username = $login->createElement('text', 'username')
->setRequired(true)
->addValidator('regex', false, array('/^[a-z0-9]*$/i'))
->addValidator('stringLength', false, array(4,15));
$password = $login->createElement('password', 'password')
->setRequired(true)
->addValidator('regex', false, array('/^[a-z0-9*]*$/i'))
->addValidator('stringLength', false, array(5,10));
$login->addElement($username)
->addElement($password)
->addElement('submit', 'login', array('label' => 'Login'));
return $login;
}
public function indexAction()
{
echo $this->loginForm();
}
public function loginAction()
{
if($this->getRequest()->isPost()){
$form = $this->loginForm();
if (!$form->isValid($_POST)) {
$this->view->message = "<font style=\"color:red; font-weight:bold;\">Invalid Input</font><br />";
$this->view->badlogin=$form;
}else{
$erg=$form->getValues();
$authAdapter = new MyWork_myauthadapter();
$authAdapter->setIdentity($erg['username']);
$authAdapter->setCredential($erg['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
$storage = $auth->getStorage();
$storage->write($authAdapter->getResultRowObject(array('spalte_mit_username','spalte_mit_rolle'),'spalte_mit_passwort'));
$this->view->message = 'Login success.';
} else {
switch ($result->getCode()){
case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
$this->view->message = '<b>Anmeldung fehlgeschlagen.</b><br />
<br />
Benutzername und/oder Passwort falsch.';
break;
case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
$this->view->message = '<b>Anmeldung fehlgeschlagen.</b><br />
<br />
Inaktiv oder gebannt.';
break;
default:
$this->view->message = '<b>Anmeldung fehlgeschlagen.</b><br />
<br />
Es ist ein Fehler aufgetreten.';
break;
}
}
}
}else{
return $this->_forward('index');
}
[/code]
Alle Fragen zum Formular an sich sollten hier geklärt werden können.
Ich werde hier nur kurz sagen, was folgende Zeilen bedeuten :
[code=php]
$authAdapter = new MyWork_myauthadapter();
$authAdapter->setIdentity($erg['username']);
$authAdapter->setCredential($erg['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
$storage = $auth->getStorage();
$storage->write($authAdapter->getResultRowObject(array('spalte_mit_username',
'spalte_mit_rolle'),'spalte_mit_passwort'));
[/code]
Also erstmal hohlen wir uns unsere Adapterklasse und übergeben dieser die Benutzereingaben. Dann lassen wir prüfen ob diese Eingaben korrekt sind. Wenn ja, dann werden die beiden Spalten spalte_mit_username und i]spalte_mit_rolle[/i] noch gespeichert, damit unser Plugin auch bei jedem Seitenaufruf die Indentität wiederfindet.
Fertig ist das komplette Usermanagement
Letztes Update : 27.09.2008
- Eine eigene Klasse die von Zend_Acl abgeleitet wird
- Ein Zend_auth Adapter
- und ein Front Controller Plugin der die User bei jedem Seitenaufruf authentifiziert
- dann noch ein Loginformular
Also erstmal legen wir einen neuen Ordner im Verzeichnis library an den ich hier MyWork nennen werde.
In diesem Ordner legen wir nun 3 Datein an :
- myacl.php
- myauth.php
- myauthadapter.php
Arbeiten wir uns nun mal von oben nach unten dutch die Datein.
Inhalt von myacl.php
[code=php]
<?php
class MyWork_myacl extends Zend_Acl
{
public function __construct(Zend_Auth $auth)
{
$this->add(new Zend_Acl_Resource('index'));
$this->addRole(new Zend_Acl_Role('gast'))
->addRole(new Zend_Acl_Role('admin'),'gast');
$this->allow('gast','index','index');
->allow('admin','index',array('neuenuser','userlöschen'));
}
}
[/code]
Die Klasse muss so benannt werden damit sie von Zend_Auoload im Unterordner gefunden wird ( wer sich also bis jetzt gewundert hat warum alle Zend Klassen mit dem Präfix 'Zend_' beginnen, dem geht jetzt wohl ein Licht auf
Was passiert in dieser Date ?
Erst definieren wir Resourcen. Wir können mit Zend_Acl nur den Zugriff von Usern auf Resourcen kontrollieren. Es macht daher sinn diese Resourcen sinnig zu bennenen. Ich benutze hier den Controllernamen.
Den Actionnamen sollten wir nicht nehmen, da man später die Action als zusätzlich behandeln kann.
Dann müssen wir Rollen ( Benutzergruppen ) anlegen.
Eine Rolle sollte immer 'gast' o.ä. heißen. Schließlich brauchen wir eine Klasse die alle nicht angemeldeten User bekommen.
Zusätzlich definiere ich nun noch eine Admingruppe.
Durch den 2. Parameter 'gast' lasse ich der Admingruppe alle Erlaubnisse von der Gruppe gast erben.
Also wenn Gast nun Zugriff auf xyz hat, dann hat die Admingruppe automatisch auch Zugriff auf jene Resource.
Als nächstes sagen wir der Klasse welche Usergruppen auf welche Resource Zugriff hat.
[code=php]allow('gast','index','index')[/code]
Gast hat nun Zugriff auf die Resource 'index' und dort auf die Action 'index'.
Admin hat nun automatisch durch die Vererbung auch Zugriff auf diese Action.
[code=php]allow('admin','index',array('neuenuser','userlöschen')[/code]
Admin hat nun Zugriff auf die Resource 'index' und dort auf die beiden Action´s 'neuenuser' und 'userlöschen'.
Inhalt von myauth.php
[code=php]
<?php
class MyWork_myauth extends Zend_Controller_Plugin_Abstract
{
private $_auth;
private $_acl;
private $_noauth = array('module' => 'default',
'controller' => 'user',
'action' => 'nouser');
private $_noacl = array('module' => 'default',
'controller' => 'error',
'action' => 'noaccess');
public function __construct($auth, $acl) {
$this->_auth = $auth;
$this->_acl = $acl;
}
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$controller = $request->getControllerName();
$action = $request->getActionName();
$module = $request->getModuleName();
$resource = $controller;
if ($this->_auth->hasIdentity()) {
$role = $this->_auth->getIdentity()->role;
} else {
$role = 'gast';
}
if (!$this->_acl->has($resource)) {
$resource = null;
}
if (!$this->_acl->isAllowed($role, $resource, $action)) {
if (!$this->_auth->hasIdentity()) {
$module = $this->_noauth['module'];
$controller = $this->_noauth['controller'];
$action = $this->_noauth['action'];
} else {
$module = $this->_noacl['module'];
$controller = $this->_noacl['controller'];
$action = $this->_noacl['action'];
}
}
$request->setModuleName($module);
$request->setControllerName($controller);
$request->setActionName($action);
}
}
[/code]
Was passiert in dieser Datei ?
Die ersten Zeilen sollten sich von selbst erklären . OOP in PHP möchte ich hier nicht näher erlätern.
Die Funktion preDispatch wird vor dem Abarbeiten des Controllers gestartet. Als parameter wird hier das Request-Objekt übergeben. Aus diesem können wir nun auslesen auf welche Seite der User gerade zugreifen möchte :
[code=php]
$controller = $request->getControllerName();
$action = $request->getActionName();
$module = $request->getModuleName();
[/code]
Nun müssen wir noch prüfen ob der User eingeloggt ist, und festlegen das unsere Resource aus Acl hier gleichzusetzten ist mit dem Controller, welcher aufgerufen werden soll.
[code=php]
$resource = $controller;
if ($this->_auth->hasIdentity()) {
$role = $this->_auth->getIdentity()->role;
} else {
$role = 'gast';
}
[/code]
Wenn der User nicht eingeloggt ist, so wird ihm die Rolle 'gast' gegeben.
Die wichtigsten Zeilen :
[code=php]
if (!$this->_acl->isAllowed($role, $resource, $action)) {
if (!$this->_auth->hasIdentity()) {
$module = $this->_noauth['module'];
$controller = $this->_noauth['controller'];
$action = $this->_noauth['action'];
} else {
$module = $this->_noacl['module'];
$controller = $this->_noacl['controller'];
$action = $this->_noacl['action'];
}
}
[/code]
Hier wird geprüft ob der User mit der Rolle $role auf die Resource $resource und dort auf die Action $action keinen Zugriff hat.
Wenn dies der Fall ist wird entschieden ob er auf die Loginseite weitergeleitet werden sollte, oder ob ihm eine Seite angezeigt werden soll, die ihm sagt, dass er keinen Zugriff auf diese Seite hat.
Schließlich werden noch die eventuell neuen Angaben an den Request weitergegeben.
So einfach ist der Hauptteil
Nun der Inhalt von myauthadapter.php
[code=php]
<?php
require_once 'Zend/Auth/Adapter/DbTable.php';
class MyWork_myauthadapter extends Zend_Auth_Adapter_DbTable
{
public $authAdapter;
public function __construct() {
$db = Zend_Registry::get('db');
parent::__construct($db);
$this->setTableName('tabelle_mit_userdaten');
$this->setIdentityColumn('spalte_mit_username');
/* Passwörter sollten verschlüsselt sein */
$this->setCredentialColumn('spalte_mit_passwort');
/* Falls verschlüsselt dann hier sagen wie */
$this->setCredentialTreatment('MD5(?)'');
}
}
[/code]
Es gibt auch andere Adapterklassen. Wer also nicht MySQL nutzt kann sich mal in dem Teil des Manuals umsehen [1]
So das wären auch schon alle wichtigen Sachen.
Als letztes noch das Loginformular. Wir bauen das Formular am besten so ein das in der selben Funktion auch der tatsächliche Loginvorgang abläuft.
[code=php]
// Klasse usw. hier erstellen
private function loginForm()
{
$login = new Zend_Form();
$login->setAction('/user/login')
->setMethod('post');
$username = $login->createElement('text', 'username')
->setRequired(true)
->addValidator('regex', false, array('/^[a-z0-9]*$/i'))
->addValidator('stringLength', false, array(4,15));
$password = $login->createElement('password', 'password')
->setRequired(true)
->addValidator('regex', false, array('/^[a-z0-9*]*$/i'))
->addValidator('stringLength', false, array(5,10));
$login->addElement($username)
->addElement($password)
->addElement('submit', 'login', array('label' => 'Login'));
return $login;
}
public function indexAction()
{
echo $this->loginForm();
}
public function loginAction()
{
if($this->getRequest()->isPost()){
$form = $this->loginForm();
if (!$form->isValid($_POST)) {
$this->view->message = "<font style=\"color:red; font-weight:bold;\">Invalid Input</font><br />";
$this->view->badlogin=$form;
}else{
$erg=$form->getValues();
$authAdapter = new MyWork_myauthadapter();
$authAdapter->setIdentity($erg['username']);
$authAdapter->setCredential($erg['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
$storage = $auth->getStorage();
$storage->write($authAdapter->getResultRowObject(array('spalte_mit_username','spalte_mit_rolle'),'spalte_mit_passwort'));
$this->view->message = 'Login success.';
} else {
switch ($result->getCode()){
case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
$this->view->message = '<b>Anmeldung fehlgeschlagen.</b><br />
<br />
Benutzername und/oder Passwort falsch.';
break;
case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
$this->view->message = '<b>Anmeldung fehlgeschlagen.</b><br />
<br />
Inaktiv oder gebannt.';
break;
default:
$this->view->message = '<b>Anmeldung fehlgeschlagen.</b><br />
<br />
Es ist ein Fehler aufgetreten.';
break;
}
}
}
}else{
return $this->_forward('index');
}
[/code]
Alle Fragen zum Formular an sich sollten hier geklärt werden können.
Ich werde hier nur kurz sagen, was folgende Zeilen bedeuten :
[code=php]
$authAdapter = new MyWork_myauthadapter();
$authAdapter->setIdentity($erg['username']);
$authAdapter->setCredential($erg['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
$storage = $auth->getStorage();
$storage->write($authAdapter->getResultRowObject(array('spalte_mit_username',
'spalte_mit_rolle'),'spalte_mit_passwort'));
[/code]
Also erstmal hohlen wir uns unsere Adapterklasse und übergeben dieser die Benutzereingaben. Dann lassen wir prüfen ob diese Eingaben korrekt sind. Wenn ja, dann werden die beiden Spalten spalte_mit_username und i]spalte_mit_rolle[/i] noch gespeichert, damit unser Plugin auch bei jedem Seitenaufruf die Indentität wiederfindet.
Fertig ist das komplette Usermanagement
Letztes Update : 27.09.2008