Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 PEAR – Einführung
2 Authentication
3 Caching
4 Date and Time
5 File Formats
6 HTTP
7 Internationalization
8 Mail
9 Networking
10 PHP
11 Text
12 Web Services
13 Benchmarking
14 Configuration
15 Database
16 File System
17 HTML
18 Images
19 Logging
20 Math
21 Numbers
22 Tools and Utilities
23 XML
24 Selbst Pakete erstellen
25 PECL
Index
Ihre Meinung?

Spacer
 <<   zurück
PHP PEAR von Carsten Möhrke
Anwendung und Entwicklung – Erweiterungen für PHP schreiben
Buch: PHP PEAR

PHP PEAR
798 S., 39,90 Euro
Rheinwerk Computing
ISBN 3-89842-580-0
gp 2 Authentication
  gp 2.1 Auth
  gp 2.2 Auth_HTTP

2 Authentication

In PEAR sind einige Pakete enthalten, die Ihnen ein einfaches Erstellen von Authentifikationsmechanismen ermöglichen. Da in vielen Web-Anwendungen eine Authentifikation erforderlich ist, können diese Pakete Ihnen viel Arbeit ersparen.

In dieser Kategorie ist ein Paket enthalten, das ich leider nicht aufnehmen konnte. Das Paket LiveUser stellt interessante Funktionen zur Verfügung, um User und deren Zugriffsrechte auf Dokumente zu verwalten. Leider haben sich bei diesem Paket öfter Änderungen in der API ergeben, und daher habe ich darauf verzichtet, das Paket aufzunehmen. Allerdings sollten Sie das Paket vielleicht im Auge behalten. Wenn es einmal fertig ist, dann könnte es Ihnen viel Arbeit abnehmen.


Rheinwerk Computing

2.1 Auth  toptop


Besprochene Version: 1.3.0.r2 Lizenz: PHP-Lizenz
Klassendatei(en): Auth/Auth.php

Auth stellt Ihnen ein Framework zur Verfügung, um ein Authentifizierungssystem für Ihre Website zu erstellen. Natürlich kann Auth mehr, als einfach nur eine Kombination aus Benutzernamen und Passwort zu überprüfen. Das Besondere an diesem Paket ist, dass Sie vielfältige Datenquellen zum Verifizieren von Benutzernamen und Passwort nutzen können. Neben einer Datenbanktabelle können Sie auch auf bestehende POP3-Accounts, SAMBA-Passwort-Dateien und viele andere Quellen zugreifen.

Die Nutzung von Auth gestaltet sich erfreulich einfach, wie das folgende Minimalbeispiel zeigt:

require_once "Auth/Auth.php"; 
 
function login_function() 
{ 
   echo "<form method=\"post\" 
            action=\"$_SERVER[PHP_SELF]\">"; 
   echo "Login <input type=\"text\" name=\"username\" /> 
            <br />"; 
   echo "Passwort <input type=\"password\" 
            name=\"password\" /><br />"; 
   echo "<input type=\"submit\" value=\"Login\" />"; 
   echo "</form>"; 
} 
 
$dsn = "mysql://netviser:geheim@localhost/netviser"; 
$my_auth = new Auth('DB', $dsn, "login_function"); 
 
$my_auth ->start(); 
 
if (true===$my_auth ->getAuth()) 
{ 
   echo ("Sie sind drin!"); 
}

Listing 2.1 Einfaches Login mithilfe von Auth

Der Konstruktor der Klasse bekommt hier drei Parameter übergeben. Beim ersten handelt es sich um die Bezeichnung des »Storage-Drivers«. Mit ihm wird festgelegt, auf welchen Datenquellen-Typ zugegriffen werden soll, um die Daten abzugleichen. Neben DB, der festlegt, dass das PEAR-Paket DB zum Zugriff auf eine Datenbank genutzt werden soll, stehen Ihnen noch die Storage-Driver aus Tabelle 2.1 zur Verfügung.


Tabelle 2.1 Storage-Driver für Auth
Abkürzung Beschreibung
'DB' Nutzt das Paket PEAR::DB, um die Daten gegen eine Datenbank zu authentifizieren.
'LDAP' Greift auf einen LDAP-Server zur Verifizierung der Nutzerdaten zu.
'SMBPasswd' Die Authentifikation der Daten erfolgt mithilfe einer Samba-Passwortdatei. Benötigt das Paket File_SMBPasswd.
'File' Ermöglicht den Zugriff auf passwd-Dateien und benötigt das Paket File_Passwd. Primär wird es sich hierbei um Passwort-Dateien von Unix-Systemen handeln, aber auch CVS, AuthUserFile und andere Typen können genutzt werden.
'POP3' Benutzername und Kennwort können mit diesem Storage-Driver gegen einen POP3-Server geprüft werden, wozu auf das Paket Net_POP3 zurückgegriffen wird.
'SOAP' Nutzt das SOAP-Protokoll zur Benutzerauthentifizierung.
'IMAP' Mit IMAP versucht das Paket sich mit einem IMAP-Server zu verbinden und sich dort mit den Daten einzuloggen.
'RADIUS' Authentifiziert gegen einen RADIUS-Server und benötigt das PEAR-Paket Auth_Radius sowie das PECL-Paket radius.
'vpopmail' Greift auf einen bestehenden vpopmail-Service zur Authentifikation zu.

Im obigen Beispiel habe ich eine Authentifikation per Datenbank genutzt, was ich auch beibehalten werde, da es sicher die Methode ist, die am häufigsten genutzt wird. Informationen zu den anderen Storage-Treibern finden Sie unter der URL http://pear.php.net/manual/en/package.authentication.auth. intro-storage.php. Das Einbinden anderer Treiber ist unproblematisch und unterscheidet sich nur durch die genutzten Parameter.

Im obigen Beispiel wird mit 'DB' als erstem Parameter das Paket PEAR::DB als Storage-Driver eingebunden. Bei dem zweiten Parameter handelt es sich um den DSN. Mit "mysql://netviser:geheim@localhost/netviser" wird ein MySQL-Datenbankserver angesprochen, der sich auf demselben Server wie der Webserver befindet. Das Login erfolgt mit dem Benutzer netviser und dem Passwort geheim, wobei die Tabelle in der Datenbank netviser erwartet wird. Weitere Informationen zum Aufbau von DSNs finden Sie im Kapitel 15.1 in dem PEAR::DB beschrieben wird.

Der dritte Wert, der dem Konstruktor übergeben wird, ist der Name der Login-Funktion. Die Login-Funktion ist die Funktion, die zur Ausgabe des Login-Formulars dient. Natürlich muss ein solches Formular nicht so minimalistisch ausgelegt sein wie in diesem Beispiel. Wichtig ist nur, dass die Felder für den Usernamen und das Passwort die Namen username und password haben. Geben Sie diesen dritten Parameter nicht an, generiert das Paket selbstständig ein Login-Formular.

In der nächsten Zeile

$my_auth ->start();

wird die eigentliche Authentifikation gestartet. Die Methode start() des neu generierten Objekts prüft, ob der Benutzer bereits eingeloggt ist. Ist das nicht der Fall, ruft sie die Funktion auf, die dem Konstruktor als dritter Parameter übergeben wurde. Diese Methode stellt den eigentlichen Kern des Pakets dar. Die meisten Pakete, die direkt mit der Authentifikation zu tun haben, liefern keine korrekten Ergebnisse, wenn Sie nicht zuvor start() aufrufen.

Bitte beachten Sie, dass das Paket auf Sessions basiert. Somit wird standardmäßig versucht, einen Cookie an den Client zu senden. Daher sollten Sie also sicherstellen, dass vor dem Aufruf der Methode keine anderen Daten wie HTML-Tags oder auch nur ein Leerzeichen an den Browser geschickt werden.

In der Zeile

if (true===$my_auth ->getAuth())

wird schließlich geprüft, ob der Benutzer sich erfolgreich authentifiziert hat. Ist das der Fall, liefert die Methode getAuth() den booleschen Wert true zurück; andernfalls ein false.

Bevor ich weiter auf die eigentliche Authentifizierung eingehe, noch ein paar Worte zur Datenbank und zur Benutzerverwaltung.

Der Zugriff auf die Datenbank wird mit diesem DSN realisiert:

mysql://netviser:geheim@localhost/netviser

Er greift also auf einen MySQL-Datenbankserver zu, der auf localhost ausgeführt wird. Die Datenbank, die genutzt wird, ist netviser, wobei der Datenbankuser den Namen netviser und das Passwort geheim hat. Bitte beachten Sie, dass es sich hierbei um den Datenbankuser handelt, der nicht mit dem User, der sich authentifizieren möchte, identisch sein muss.

Wird der DSN in dieser Form übergeben, geht das Paket davon aus, dass die Tabelle auth heißt und die Spalten für Usernamen und Passwort die Namen username und password haben. Für die Spalte username ist keine fest definierte Länge vorgesehen. Die Spalte password hingegen muss eine Mindestlänge von 32 Zeichen aufweisen, da das Passwort als ein MD5-Hash abgelegt wird, der 32 Zeichen lang ist. Im einfachsten Fall können Sie die Tabelle also mit folgendem Befehl anlegen:

CREATE TABLE auth ( 
   username varchar(30) primary key not null, 
   password varchar(32) not null 
);

Zwar wäre es nicht unbedingt nötig, die Spalte username als Primärschlüssel zu definieren, allerdings hat das den Vorteil, dass Benutzernamen nicht doppelt vergeben werden können. Benötigt Ihre Anwendung noch weitere Spalten, in denen z. B. der Vor- und Nachname abgelegt werden, so können Sie diese ohne Probleme in die Tabelle integrieren.

Um Sie in Ihrer Anwendung nicht auf diese festgelegten Namen zu beschränken, können Sie auch andere Namen nutzen. In diesem Fall bekommt der Konstruktor als zweiten Parameter nicht direkt einen DSN, sondern ein assoziatives Array mit vier Elementen übergeben. Es gibt zum Ersten ein Element mit dem Schlüssel dsn, das den eigentlichen DSN enthält. Des Weiteren ist ein Element table zu definieren, das den Namen der Tabelle enthält. Die Schlüssel usernamecol und passwordcol verweisen schließlich auf die Spaltennamen der Spalten für die Benutzernamen und die Passwörter.

$params = array( 
          "dsn"=>"mysql://netviser:geheim@localhost/netviser", 
          "table"=>"User_Tabelle", 
          "usernamecol" => "benutzernamen", 
          "passwordcol" => "passwoerter" 
         );

Benutzerverwaltung mit Auth

Da die Datenbanktabelle, nachdem sie angelegt worden ist, zunächst keine User enthält, müssen Sie diese noch anlegen. Auth sieht auch hierfür Funktionalitäten vor, so dass Sie damit neue User anlegen können. Der Code zum Anlegen von Usern ist schon ein wenig umfangreicher. An dieser Stelle muss nämlich nicht nur geprüft werden, ob es sich um einen gültigen Benutzer handelt. Da nicht jeder User die Möglichkeit haben soll, die Benutzer zu verwalten, ist eine zusätzliche Abfrage notwendig, ob es sich um einen bzw. den Administrator handelt.

require_once ("Auth.php"); 
require_once ("PEAR.php"); 
 
// Gibt das Login-Formular aus 
function login_function() 
{ 
   echo "<form method=\"post\" 
         action=\"$_SERVER[PHP_SELF]\">"; 
   echo "Login <input type=\"text\" name=\"username\" /> 
         <br />"; 
   echo "Passwort <input type=\"password\" 
         name=\"password\" /><br />"; 
   echo "<input type=\"submit\" value=\"Login\" />"; 
   echo "</form>"; 
} 
 
// Gibt das Formular zum Anlegen eines neuen Users aus 
function create_user_form() 
{ 
   echo "<form method=\"post\" 
         action=\"$_SERVER[PHP_SELF]\">"; 
   echo ("<b>Neuen User anlegen</b><br />"); 
   echo "Login <input type=\"text\" name=\"new_user\" /> 
         <br />"; 
   echo "Passwort <input type=\"password\" 
         name=\"password1\" /><br />"; 
   echo "Passwort wiederholen <input type=\"password\" 
         name=\"password2\" /><br />"; 
   echo "<input type=\"submit\" value=\"Login\" />"; 
   echo "</form>"; 
} 
 
$dsn = "mysql://netviser:geheim@localhost/netviser"; 
// Neues Auth-Objekt 
$my_auth=new Auth ("DB",$dsn,"login_function"); 
// Authentifizieren 
$my_auth->start(); 
// Erfolgreich authentifiziert && User ist admin? 
if (true===$my_auth->getAuth() && 
    "admin"=== $my_auth->getUsername()) 
{ 
   // Muss das Formular zum Anlegen des 
   // Benutzers ausgegeben werden? 
   if (false===isset($_POST["new_user"])) 
   {  // Ja, Formular ausgeben 
      create_user_form(); 
   } 
   else 
   {  // Nein, Benutzer anlegen 
      $password1=$_POST["password1"]; 
      $password2=$_POST["password2"]; 
      $new_user=$_POST["new_user"]; 
      // Passwoerter korrekt eingegeben? 
      if ($password1 === $password2) 
      { 
         // Neuen User anlegen 
         $erg=$my_auth->addUser($new_user,$password1); 
         // Ist ein Fehler aufgetreten? 
         if (true===$erg) 
         { 
            echo "User angelegt"; 
         } 
         else 
         { 
            // Fehlermeldung ausgeben 
            echo "User nicht angelegt!<br />Fehlermeldung: "; 
            echo ($erg->getMessage()); 
         } 
      } 
      else 
      { 
         echo "Passw&ouml;rter stimmen nicht &uuml;berein!"; 
      } 
   } 
}

Listing 2.2 Script zum Anlegen von neuen Usern

Um sicherzustellen, dass der Username und das Passwort korrekt sind, führt das Script aus Listing 2.2 zuerst eine normale Authentifizierung durch. In der if-Abfrage, die den Erfolg der Authentifikation prüft, wird aber zusätzlich noch getestet, ob der eingegebene Benutzername admin entspricht. Mit der Methode getUsername() können Sie also den Namen auslesen, mit dem der User sich eingeloggt hat. Eine derart statische Prüfung ist zwar für dieses Beispiel ausreichend, für eine größere Installation, in der es mehrere Administratoren gibt, müsste natürlich ein anderer Mechanismus vorgesehen werden.

Bitte vergessen Sie nicht, dass Sie erst einen Benutzer admin beim System angemeldet haben müssen, bevor die Abfrage überhaupt funktionieren kann. Zum Anlegen des ersten Users sollte die if-Abfrage also noch nicht im Code stehen.

Nach der Prüfung der Benutzerdaten muss das Script unterscheiden, ob das Formular zum Anlegen eines neuen Benutzers ausgegeben wird oder ob die Daten bereits eingegeben wurden und in die Datenbank geschrieben werden können. Hierfür ist die if-Abfrage

if (false===isset($_POST["new_user"]))

zuständig. Das Formular zur Abfrage der User-Daten beinhaltet drei Felder: eines für den Benutzernamen und zwei für die Eingabe des Passworts. Das Passwort wird doppelt eingegeben, um Tippfehler auszuschließen.

Die Identität der beiden Passwort-Eingaben wird geprüft, bevor der User mit der Methode addUser() neu angelegt wird. Sie bekommt den Namen sowie das Passwort des neuen Users übergeben. Die Methode liefert ein true, wenn der User angelegt werden konnte, oder ein PEAR_Error-Objekt, wenn das nicht der Fall ist. Im Falle eines Fehlers generiert das Script eine entsprechende Meldung und liest den Fehler, den das Paket festgestellt hat, mit Hilfe der PEAR_Error-Methode getMessage() aus.

In diesem Beispiel ist es nicht notwendig zu testen, ob ein Benutzername bereits existiert, da datenbankseitig sichergestellt wird, dass ein doppeltes Vorkommen ausgeschlossen ist. Allerdings möchte ich das nicht für alle Speicher-Container garantieren, da diese Container mit Hilfe von anderen Paketen verwaltet werden. Um vor dem Anlegen eines neuen Users zu prüfen, ob der Benutzername bereits vergeben ist, können Sie die Methode listUsers() nutzen. Sie liest alle Usernamen und Kennwörter aus dem gewählten Container aus und liefert sie als Array zurück. Hierbei handelt es sich um ein indiziertes Array, das wiederum aus einzelnen assoziativen Arrays besteht, die ihrerseits den Benutzernamen und das dazugehörige kodierte Passwort enthalten.

array(2) { 
  [0]=> 
  array(2) { 
    ["username"]=> 
    string(5) "Peter" 
    ["password"]=> 
    string(32) "e8636ea013e682faf61f56ce1cb1ab5c" 
  } 
  [1]=> 
  array(2) { 
    ["username"]=> 
    string(8) "Paulchen" 
    ["password"]=> 
    string(32) "496da3f1d1378bab4e2e750ab8dfa5ec" 
  } 
}

Auf dieser Basis können Sie mit wenigen Zeilen Code prüfen, ob ein Username bereits existiert, wie die Funktion aus Listing 2.3 zeigt:

function user_exists($user, $auth_obj) 
{ 
   $userlist=$auth_obj->listUsers(); 
   foreach ($userlist as $key => $userdata) 
   { 
      if ($userdata["username"]===$user) 
      { 
         return true; 
      } 
   } 
   return false; 
}

Listing 2.3 Funktion zum Testen, ob ein Username bereits vergeben ist

Die Funktion bekommt den Usernamen übergeben, der gesucht werden soll, und vergleicht ihn dann mit allen Usernamen, die im gewählten Container vorhanden sind. Wird der Name gefunden, bricht die Funktion ab und liefert true; andernfalls ist der Rückgabewert false.

Um ein Passwort zu ändern, steht die Methode changePassword() zur Verfügung. Sie bekommt einen Benutzernamen und das neue Passwort übergeben:

$erg=$my_auth->changePasswort("Paul","totalGeheim");

In diesem Beispiel wird die Methode des Objekts $my_auth aufgerufen und ändert das Passwort des Benutzers Paul. Die Methode kann true, ein PEAR_Error-Objekt oder die Konstante AUTH_METHOD_NOT_SUPPORTED zurückgeben, wenn der gewählte Container das Ändern des Passworts nicht unterstützt.

Natürlich ist auch eine Methode vorgesehen, mit der Sie einen existierenden User wieder löschen können. Die Methode removeUser() bekommt den Namen übergeben, der entfernt werden soll. Ist die Löschung erfolgreich, gibt sie true zurück. Sollte es nicht möglich sein, den User zu entfernen, wird ein PEAR_Error-Objekt zurückgegeben.

Weitere Funktionalitäten von Auth

Neben den schon besprochenen Funktionen bietet Auth noch einige weitere hilfreiche Funktionalitäten. Am wichtigsten ist sicher die Methode logout(), mit der eine User-Session beendet werden kann. Sie bekommt keine Parameter übergeben.

Das Verhalten des Pakets kann mit einigen Eigenschaften bzw. Methoden gesteuert werden, die diese Eigenschaften beeinflussen. Mit der Methode setAllowLogin() können Sie steuern, ob ein Login überhaupt möglich sein soll. Sie bekommt einen booleschen Wert übergeben, wobei ein false die Login-Funktionalität ausschaltet. Das ist immer dann sinnvoll, wenn das System aufgrund von Wartungsarbeiten oder Ähnlichem vorübergehend nicht zur Verfügung steht.

Das Zeitverhalten einer Session können Sie mit den Methoden setExpire() und setIdle() steuern. Standardmäßig ist ein Login so lange gültig, wie das Browserfenster geöffnet bleibt. Die Expire-Time legt fest, wie lange eine Session gültig bleiben soll, wohingegen die Idle-Time bestimmt, wie lange ein User untätig sein darf, bevor er automatisch ausgeloggt wird.

Die Methoden setIdle() und setExpire() bekommen beide eine Zeitangabe in Sekunden übergeben. Mit dem zweiten optionalen Parameter können Sie festlegen, ob die Sekunden zu den bestehenden Timeout-Angaben addiert werden sollen oder ob es sich um einen neuen, absoluten Wert handelt. Wenn Sie ein true als zweiten Parameter übergeben, werden die Sekunden addiert, bei keiner Angabe oder einem false wird die Zeit als absoluter Wert interpretiert.

Ungemein hilfreich sind auch die verschiedenen Callback-Funktionen, die das Paket unterstützt. Hierbei handelt es sich um Funktionen, die zu einem bestimmten Zeitpunkt, also z. B. nach dem Login oder dem Logout, automatisch vom System ausgeführt werden. Dazu müssen sie allerdings erst angemeldet werden, wozu die Methoden aus Tabelle 2.2 vorgesehen sind.


Tabelle 2.2 Methoden zum Festlegen von Callback-Funktionen
Methode Erläuterung
setLoginCallback() Legt eine Funktion fest, die nach einem erfolgreichen Login ausgeführt wird.
setLogoutCallback() Die Funktion, deren Name übergeben wird, wird nach dem Logout ausgeführt.
setFailedLoginCallback() Die hiermit bestimmte Funktion wird jedes Mal ausgeführt, wenn ein Login-Versuch fehlschlägt. Hierzu muss der Benutzer allerdings etwas in das Login-Formular eingegeben haben. Leere Felder werden nicht als Login gewertet.

Im folgenden Beispiel wird die Funktion fehlgeschlagen() als Callback für ein missglücktes Login festgelegt.

// Weitere Funktionsdeklaration und Inkludierung von Auth 
function fehlgeschlagen() 
{ 
   echo "Login fehlgeschlagen!<br />Bitte erneut versuchen!"; 
} 
 
$my_auth=new Auth ("DB", $dsn, "login_function"); 
$my_auth->setLoginFailedCallback("fehlgeschlagen"); 
$my_auth->start();

Bitte beachten Sie, dass die Callback-Funktionen, die sich auf das Login beziehen, festgelegt werden müssen, bevor die Methode start() aufgerufen wird.

 <<   zurück
     
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: PHP PEAR
PHP PEAR
Jetzt Buch bestellen!
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: PHP 5.6 und MySQL 5.7






 PHP 5.6 und
 MySQL 5.7


Zum Rheinwerk-Shop: Einstieg in PHP 5.6 und MySQL 5.6






 Einstieg in PHP 5.6
 und MySQL 5.6


Zum Rheinwerk-Shop: Responsive Webdesign






 Responsive Webdesign


Zum Rheinwerk-Shop: Moderne Websites entwickeln






 Moderne Websites
 entwickeln


Zum Rheinwerk-Shop: MySQL 5.6






 MySQL 5.6


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo








Copyright © Rheinwerk Verlag GmbH 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern