Hallo!
Ich habe die Auflage bekommen in meinem aktuellen Projekt eine Logout-Funktion für die verwendete basic authentication zu implementieren.
Naja, zunächst sagen alle "das geht nicht...", aber ich habe ja nicht nur HTTP-alleine zur Verfügung. Ich verwende neben HTTP-Auth auch Sessions. Das versetzt mich in die Lage, zusätzliche Informationen zum Client zu speichern, mit dessen Hilfe zusammen mit einigen Annahmen und der Möglichkeit eigene Header zu senden, ich glaube dass ein Logout möglich ist.
Mit Logout meine ich, dass wenn der User in der Anwendung auf einen Button "logout" klickt, dass er dann auf eine Seite "sie wurden ausgeloggt..." weitergeleitet wird, und bevor er wieder die auf irgendwelche der geschützten Seite zugreifen kann wieder neue Daten in das HTTP-Auth Popup eingeben müssen, auch wenn das Browserfenster nicht geschlossen wurde.
Im Prinzip wäre das ganz einfach wenn sich alle Browser an die HTTP-Spec halten würden, aber das tun sie nicht, zumindest der Mozilla in diesem Fall. Gemäß rfc2616(HTTP/1.1) und rfc1945(HTTP/1.0) sollen die Clients, wenn Sie 401 als Response erhalten nachdem(!) sie bereits an selbigen host/realm Auth-Daten gesendet haben, diese als ungültig betrachten, und eine neue Eingabe der Daten anfordern. Das macht der IE auch, nur der Mozilla sendet die Daten einfach nochmal. Also reicht es nicht bei klick auf "Logout" einfach einen 401-Header zu senden. Die einzig zuverlässige und IMHO kein Protokoll verletzende Möglichkeit die ich gefunden habe, ist das Verändern des realms in diesem Fall, das heißt ich füge einen unique-String in den realm-string ein, so dass der Client keine Daten mehr aus seine Cache verwendet und den User erneut zur Authentifzierung auffordert. Als Unique-String verwende ich die aktuelle Uhrzeit, sekundengenau.
Das hat aber den Nachteil, dass der user seine Auth-Daten nicht speichern kann wenn er das möchte, da jedesmal neue Daten angefordert werden und der Client davon ausgeht, dass es sich um ein völlig anderes Projekt handelt.
Daher habe ich mir überlegt, wenn der User sich erstmalig einloggt, erkenne ich das daran, dass er im Gegensatz zu einem "relogin" (2. Login innerhalb einer "Browsersession")_keine_ Auth-Daten mitsendet. Das heißt am Vorhandensein der HTTP-Auth Daten kann ich sehen ob es sich um eine neue oder eine laufende "Browserfenstersession" handelt.
Ich habe das Script mal hochgeladen, wäre nett wenn Ihr mal ausprobieren könntet ob es bei euch auch funktioniert oder eben nicht. Mich interessiert auch was Ihr allgemein ganz realistisch davon haltet.
Das Script: http://tmp.knet-systems.de/auth.php
Der Source: http://tmp.knet-systems.de/auth_source.php
Aufgrund von Änderungen am Namenserver kann es sein dass die Dateien nicht sofort gefunden werden.
Daher der Code schonmal vorab:
Viele Grüße
Andreas
<?php
// Sessions sind Voraussetzung
session_start();
// user ausloggen (säter vielleicht eher mit session_destroy()...)
if($_REQUEST['action'] == 'logout') {
$_SESSION['auth']['status'] = 'off';
display_logout();
}
// prüfen ob user eingeloggt ist
if ($_SESSION['auth']['status'] != 'on') {
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// user sendet keine Auth-Daten -> komplett neuer Login, noch kein Login im aktuellen Browserfenster gewesen
$_SESSION['auth']['newlogin'] = 1;
authenticate();
}
else {
// user sendet Auth-Daten: entweder durch Aufforderung oben, oder wegen "relogin"
if ($_SESSION['auth']['newlogin'] == 1) {
// neue Daten eingegeben
check_auth();
$_SESSION['auth']['newlogin'] = 0;
$_SESSION['auth']['status'] = 'on';
display_login();
}
else {
// 'relogin': damit auch Mozilla Auth-Daten nicht automatisch aus dem Cache schickt -> sende "unique realm"
$_SESSION['auth']['newlogin'] = 1;
re_authenticate();
}
}
}
else {
display_login();
}
// Authentifizierungs Header senden
function authenticate() {
header ('HTTP/1.0 401 Unauthorized');
header ("WWW-Authenticate: Basic realm="Test Authentication System"");
die ("You must enter a valid login ID and password to access this resource\n");
}
// Authentifizierungs Header mit "unique realm" senden (damit Mozilla bei Relogin nicht Auth-Daten aus dem Cache verwendet)
function re_authenticate() {
$unique = date ('d.m.Y, h.i.s');
header ('HTTP/1.0 401 Unauthorized');
header ("WWW-Authenticate: Basic realm="Test Re-Authentication System ($unique)"");
die ("You must enter a valid login ID and password to access this resource\n");
}
// HTML Quellcode für "logged in" Seite
function display_login() {
die ('<html><body><h3>User logged in</h3><a href="auth.php?action=logout">logout</a><br></body></html>');
}
// HTML Quellcode für "logged out" Seite
function display_logout() {
die ('<html><body><h3>User logged out</h3><a href="auth.php">login again</a><br></body></html>');
}
// Authentifzierung mit DB... durchführen
function check_auth() {
// check Auth...
}
?>