Überschneidungen zw. Auth, User und Request-Daten
Andreas Korthaus
- programmiertechnik
Hallo!
Ich habe 3 Klassen:
Request-Klasse: Analysiert den Request und stellt enstsprechend Daten über eien Schnittstelle zur Verfügung
Auth-Klasse: holt sich aus der Request-KLasse den per HTTP mitgesendeten USernamen udn validiert diesen
User-Klasse: ermittelt alle Daten des Users udn stellt diese "über schnittstelle"(Scripte greifen direkt auf die Variablen Eigenschafteb der Klasse zu) zur Verfügung
Jetzt habe ich das Problem, das als erstes die Auth-Klasse die Userdaten aus der Datenbank ermittelt, um diese zu validieren, und danach holt sich die User-Klasse den username und schickt im Prinzip dieselbe Abfrage an die Datenbank. Das ist nicht schön.
Habt Ihr eine Idee wie ich das gleichzeitig "schön" und ohne 2. Abfrage hinbekomme?
Ich könnte direkt alle Daten in der Auth-Klasse ermitteln, aber das wäre sehr unsauber, da das ja nichts mehr mit der Authentifizierung zu tun hat. Ich könnte auch in der User-Klasse zuerst die Daten ermitteln, und _danach_ die Auth-Klasse validieren lasse. Aber das ist auf alle Fälle der falsche Weg.
Oder geht es hier nur entwedr performant _oder_ schön? Wobei schön kein Selbstzweck ist, sondern eine saubere Programmierung vereinfach am Ende auch einiges!
Grüße
Andreas
Hi Andreas,
Jetzt habe ich das Problem, das als erstes die Auth-Klasse die Userdaten aus der Datenbank ermittelt, um diese zu validieren, und danach holt sich die User-Klasse den username und schickt im Prinzip dieselbe Abfrage an die Datenbank. Das ist nicht schön.
Du hast eine Diskrepanz zwischen der externen und der internen Repräsentation Deiner Objekte: Intern speicherst Du alles in einer Tabelle, extern sind es zwei verschiedene Objekte. Deshalb kommt Dir die Implementierung "nicht schön" vor. Sie ist jedenfalls nicht konsistent - sie ist nicht leicht zu verstehen. Und das ist für ihren Anwender, den Programmierer, ein Nachteil.
Habt Ihr eine Idee wie ich das gleichzeitig "schön" und ohne 2. Abfrage hinbekomme?
Hm. Ich würde den User als Objekt sehen, nicht aber die Authentifizierung desselben. Wieso ist das nicht einfach eine Methode dieses Objektes?
Ich könnte direkt alle Daten in der Auth-Klasse ermitteln, aber das wäre sehr unsauber, da das ja nichts mehr mit der Authentifizierung zu tun hat.
Das kommt auf die Definition der Aufgaben-Zuständigkeiten an. Wenn Deine User-Klasse dafür zuständig ist, alles zu tun, was mit den Attributen eines Users zu tun hat (also auch die Authentifizierung), dann sehe ich keine Unsauberkeit.
Ich könnte auch in der User-Klasse zuerst die Daten ermitteln, und _danach_ die Auth-Klasse validieren lasse. Aber das ist auf alle Fälle der falsche Weg.
Warum nicht beides simultan? Als SQL-Query formuliert:
SELECT attributes
FROM user_table
WHERE username="<value1>"
AND password="<value2>";
Klappt die Authentifizierung, dann bekommst Du eine Trefferzeile (ich impliziere, daß 'username' primary key ist), wenn nicht, dann bekommst Du nichts.
Viele Grüße
Michael
Hi Michael!
Hm. Ich würde den User als Objekt sehen, nicht aber die Authentifizierung desselben. Wieso ist das nicht einfach eine Methode dieses Objektes?
Eigentlich wollt ich hier ein PEAR-Package verwenden. Das ließe sich zwar auch in die User-Klasse implementieren, aber die Authentifizierung ist erheblich komplexer als die User-Klasse, daher habe ich Probleme das so rum zu mischen. Ich würde das schon gerne trennen. Außerdem ist mir eingefallen das ich bei PEAR::Auth gar nichts mit der eigentlichen Authentifizierung zu tun habe, d.h. daher kan ichgar nicht an die Date kommen, und ich kann der Klasse auch keine User-Daten übergeben, da die die Authentifizierung komplett übernimmt. Ich muß dann wohl 2 Abfragen in Kauf nehmen, aber auf der anderen Seite, wieviel Performance kostet das? Ich habe sowieso immer zig Datenbank-Abfragen, d.h. die Datenbank-Verbindung muß eh hergestellt werden, also geht da kaum was verloren durch eine Tabelle mit maximal 20 CHAR-Spalten mit höchtens ein paar 1000 Datensätzen.
Das kommt auf die Definition der Aufgaben-Zuständigkeiten an. Wenn Deine User-Klasse dafür zuständig ist, alles zu tun, was mit den Attributen eines Users zu tun hat (also auch die Authentifizierung), dann sehe ich keine Unsauberkeit.
Hm. Mein Problem liegt wohl darin das ich die Klassen größten Teils noch als Datencontainer betrachte.
Warum nicht beides simultan? Als SQL-Query formuliert:
SELECT attributes
FROM user_table
WHERE username="<value1>"
AND password="<value2>";
Klappt die Authentifizierung, dann bekommst Du eine Trefferzeile (ich impliziere, daß 'username' primary key ist), wenn nicht, dann bekommst Du nichts.
Das war auch meine erste Idee, hatte dann aber gedacht das hierbei Fehler auftreten können die ich dann gerne in der Auth-Klasse abfangen würde, und nicht in der User-Klasse, oder es können mehrals 1 Datensatz gefunden werden - wobei das dann eien fehlerhafte implementiereung der Schreib-zugriffe wäre, also kann ich das durchaus verwenden. Vielleicht sollte ich doch auf PEAR::Auth verzichten, und doch was eigenes stricken, da könnte ich das dann so machen. Aber mal ehrlich, meinst Du diese eine Datenbank-Abfrage extra ist diesen Aufwand wert? Wieviel würde gespart? 0.02 Sekunden?
Viele Grüße
Andreas
Hi Andreas,
Ich muß dann wohl 2 Abfragen in Kauf nehmen, aber auf der anderen Seite, wieviel Performance kostet das?
mehr als eine. ;-) Wieviele Anforderungen wird dieses System verarbeiten müssen?
Ich habe sowieso immer zig Datenbank-Abfragen, d.h. die Datenbank-Verbindung muß eh hergestellt werden, also geht da kaum was verloren durch eine Tabelle mit maximal 20 CHAR-Spalten mit höchtens ein paar 1000 Datensätzen.
_Das_ ist die klassische Tabelle zum im RAM halten. ;-)
Warum nicht beides simultan?
Das war auch meine erste Idee, hatte dann aber gedacht das hierbei Fehler auftreten können die ich dann gerne in der Auth-Klasse abfangen würde, und nicht in der User-Klasse,
Dieses Problem stellt sich nicht, wenn Du gar keine Auth-Klasse hast.
oder es können mehrals 1 Datensatz gefunden werden
Nicht, wenn Dein Datenmodell das von vorn herein verhindert. Integrität ist keine Frage von Algorithmen, sondern von Konzepten. Genau dafür gibt es UNIQUE INDEXes ...
Aber mal ehrlich, meinst Du diese eine Datenbank-Abfrage extra ist diesen Aufwand wert? Wieviel würde gespart? 0.02 Sekunden?
Keine Ahnung. Dir ging es doch ursprünglich um die Ästhetik des Modells - darauf bin ich jedenfalls in die Diskussion eingestiegen ...
Viele Grüße
Michael
Halihallo Andreas
Jetzt habe ich das Problem, das als erstes die Auth-Klasse die Userdaten aus der Datenbank ermittelt, um diese zu validieren, und danach holt sich die User-Klasse den username und schickt im Prinzip dieselbe Abfrage an die Datenbank. Das ist nicht schön.
Habt Ihr eine Idee wie ich das gleichzeitig "schön" und ohne 2. Abfrage hinbekomme?
Ich versuche mal etwas allgemein zu formulieren:
Wenn zwei Klassen gleiche funktionen/daten haben, nenne ich das Coderedundanz.
Coderedundanz, wie in der Datebankmodellierung, verhindert man, indem man gleiche
Funktionen/Daten ausgliedert und als separate (ergänzende) Struktur ablegt. Auf dein
Beispiel bezogen hiesse das, dass du einen Layer (Schicht) unter die User und Auth Klasse
legst, welche die Daten einliest und im Speicher hält. Beide Klassen würden dann auf
diese "gemeinsame" Speicherrepräsentation der Daten zugreifen. Der Thread ist leider
schon im Archiv verschwunden, aber vielleicht brauchst du auch sowas, was ich brauche:
</archiv/2003/1/34949/#m190860>. Einen Datenbank-Layer, der die Daten (im RAM)
speichert; und Entity-Klassen (User, Auth), welche diese Daten dann holen. Das ganze ist,
wie in deinem anderen Thread, ein Caching-Problem; die Daten sollen nicht erneut
eingelesen werden müssen, sondern im Speicher gehalten werden.
Hoffe, dass diese etwas allgemein formulierte Antwort dennoch auf dein Thema/Frage passt.
Viele Grüsse und HTH
Philipp
Halihallo Andreas
[...]
Das war wohl etwas sehr weit gedacht. Ich würde dennoch ein Caching-Konzept empfehlen,
welches die Daten an einem zentralen Ort speichert. Du hast ja in einem anderen Posting
gesagt, dass du die Klasse User auch als Datencontainer verwendest, wenn also eine
Instanz von User alle Daten desselben enthält, warum benutzt du diese nicht um sie in
Auth zu verwenden? - Die Klasse Auth wäre demnach eine "Auslagerung" spezieller Methoden,
welche auf Daten der User-Instanz zugreift. Konkret würde ich mir das so vorstellen:
$user = new User( id => 'testuser' ); # instanziieren
$user->_load; # daten einlesen (ggf. implizit durch eine
# getData-Methode, die merkt, dass noch keine
# gelesen wurden)
$auth = new Auth( pwd => 'testpass' ); # auth-objekt mit eingegebenem Passwort inst.
$auth->user_authentication( $user ) # überprüft, ob das Passwort mit den Daten
# aus $user authentisch sind.
if ($auth->isAuthenticated) { # user eingeloggt, falls authentisch.
$user->setStatus( MSG_SUCCESSFUL_LOGGED_IN );
}
Du bräuchtest demnach nur eine Datenbank-Abfrage, nämlich etwas in der Art
SELECT * FROM webapp_user WHERE user_login="'.$user->id.'"
diesen müsstest du sowieso ausführen, wenn du auf Daten des Users zugreifen wolltest.
Viele Grüsse und HTH
Philipp