Archiv verlassen und diese Seite im Standarddesign anzeigen : Login auf Ajax-Seiten
mittelding
2010-05-19, 17:42:46
Hallo!
Habe zuletzt etwas mit Ajax rumgespielt und würde meiner Seite nun gerne einen Userbereich mit Loginfunktion hinzufügen. Und hier gehts schon los:
Stehe ich gerade mächtig auf dem Schlauch, oder ist das ganze etwa gar einfacher als auf einer non-Ajax-Seite? Grob gesagt verweilt ein User ja ständig auf der index.php und läd keine neuen Seiten, sondern es werden lediglich per JS PHP-Dateien abgefragt.
Das bedeutet ja eigentlich, dass ich in der Index.php eine neue Session erzeugen könnte und dann an die PHP-Skripte weiterleiten müsste. Ich müsste mir aber keine Gedanken über die Weitergabe der Session-id via Cookie oder Url (get) machen, richtig? index.php bleibt ja index.php.
Habe ich da zu kurz gedacht, oder war es das wirklich schon?
Dann zu einer zweiten Frage - wie ich das ganze im Detail umsetze.
Es sei angemerkt, dass ich keinen dauerhaften Login brauche, welcher über Wochen anhält (indem z.B. user und pass in einem Cookie stehen).
Mein bisheriger Plan:
1. Ich erzeuge in der index.php beim ersten Besuch eine neue Session und speichere die session-ID samt User-IP in einer Datenbank (aus Schutz vor Sessionklau).
2. Wenn der User sich erfolgreich einloggt, setze ich in der Session eine Variable "loggedIn" auf true - dürfte ja eigentlich kein Sicherheitsrisiko darstellen, da nur der Server die Session manipulieren darf? Alternativ könnte man das loggedIn auch in der DB setzen.
3. Wenn per AJAX eine Seite geladen wird, die zum geschützen Bereich gehört, dann wird die Session-ID und die IP an das aufgerufene PHP-Skript übermittelt. Dieses schaut ob loggedIn auf true ist und geht anschließend in die DB, um zu schauen ob die Session-ID / IP Kombination existiert. Wenn ja dann wird der geschütze Content ausgegeben.
4. Wenn sich der User ausloggt, dann wird die Session-ID zerstört. An der Datenbank muss ich ja eigentlich nichts ändern, da beim nächsten Betreten der Seite eine neue Session-ID erzeugt wird und samt IP wieder in die DB geschrieben wird.
5. Läuft die Session-ID ab, so ist der USer automatisch ausgeloggt.
Was haltet ihr davon? Habe nicht viel Erfahrung damit und sowas noch nie gemacht, eventuell könntet ihr kurz was dazu schreiben.
Optional würde ich doch gerne Cookies benutzen - aber nur um die Session-ID dort abzuspeichern. Ich erhoffe mir damit, dass der User die index.php mal kurz verlassen kann und auf eine fremde Seite gehen kann - und noch eingeloggt ist, wenn er zurückkommt.
Vielen Dank!
Marscel
2010-05-19, 20:50:21
Also grundsätzlich, weil mir das bei dir nicht eindeutig klingt, damit der User irgendwie an Sitzungsdaten auf dem Server gelangt, musst du eine SessionID bei JEDER Anfrage an JEDES Skript - auch über XmlHttpRequest - das sich dafür interessiert, an den Server senden. Ob das mittels GET, POST oder COOKIE passiert ist egal, man kann sowas auch cookie-los machen (dann werden SessionIDs eben in den Request gepackt und man sollte ja keine Links [im eigenen Netzwerk] weitergeben, dann ist nämlich jemand eingeloggt, der es vllt nicht sein soll).
Was auch immer du an Sessions in der index.php erzeugst - dadurch, dass der User quasi in der Browser-Addresszeile bei "index.php" bleibt und den Rest per AJAX tut, wird per sé erstmal nichts persistent. Wie geschrieben, musst du dem User dafür einmal seine ID nennen, die er dann bei jeder Anfrage erneut versendet.
$loggedIn ist ein bisschen irreführend (wenn register_globals "on" in den php-settings ist, kannst du der URL '?loggedIn=1' hinzufügen und du wärst eingeloggt, nur um potentielle Sicherheitslücken zu klären). Wenn bei dir nur angemeldete User eine Session erhalten, guckst du in der Tabelle nach, ob übermittelte Session-ID in Kombination mit der IP-Addresse (die muss nicht explizit übermittelt werden, die Natur des Webprotokolls macht es möglich, dass man weiß, wer die Anfrage gestellt hat) existieren, (und optional, ob sie auch noch im Zeitfenster liegen) und wenn ja, für welchen User die angelegt wurde. Wenn da nichts ist, verfällt die übermittelte Sitzungs-ID und der User ist einfach nicht drin und das Skript verfährt dementsprechend.
Dann wärs noch wichtig zu entscheiden, ob die Sitzung mit jeder Anfrage verlängert werden soll, dass man bei Aktivität quasi unendlich dran sitzen kann, und wenn sie denn mal zu lange inaktiv war oder einfach abläuft, dass man - für den Nutzer vllt interessant - mitgeteilt kriegt, dass man draußen ist. Nicht, dass man sich wundert, warum plötzlich keine Seite mehr korrekt geladen werden, wenn irgendwo noch "Angemeldet als: " steht.
mittelding
2010-05-19, 21:33:11
Vielen Dank schonmal!
Da kommen mir noch ein paar Fragen:
Also grundsätzlich, weil mir das bei dir nicht eindeutig klingt, damit der User irgendwie an Sitzungsdaten auf dem Server gelangt, musst du eine SessionID bei JEDER Anfrage an JEDES Skript - auch über XmlHttpRequest - das sich dafür interessiert, an den Server senden.
Also bei Seiten, die geschützt werden sollen, ist das für mich logisch. Aber bei "öffentlichen" Seiten kann ich mir die Geschichte ja sparen, richtig? Sprich nicht einmal session_start() verwenden.
$loggedIn ist ein bisschen irreführend (wenn register_globals "on" in den php-settings ist, kannst du der URL '?loggedIn=1' hinzufügen und du wärst eingeloggt, nur um potentielle Sicherheitslücken zu klären).
Also register_globals sind aus imho, aber wenn man $SESSION verwendet dürfte das eh egal sein denke ich. Aber von der loggedIn Idee bin ich eh abgekommen, dazu mehr weiter unten.
Wenn bei dir nur angemeldete User eine Session erhalten, guckst du in der Tabelle nach, ob übermittelte Session-ID in Kombination mit der IP-Addresse (die muss nicht explizit übermittelt werden, die Natur des Webprotokolls macht es möglich, dass man weiß, wer die Anfrage gestellt hat) existieren, (und optional, ob sie auch noch im Zeitfenster liegen) und wenn ja, für welchen User die angelegt wurde. Wenn da nichts ist, verfällt die übermittelte Sitzungs-ID und der User ist einfach nicht drin und das Skript verfährt dementsprechend.
Könnte ich eine Vorüberprüfung machen und wir so eventuell den DB-Query sparen, als auch das IP-Feld in MySQL?
Idee:
Ich speichere beim Login die IP des Users in der Session, nicht in der DB.
Beim Aufruf einer geschützten Seite prüfe ich:
if(!isset($SESSION['IP'] || $_SESSION['IP'] != $_SERVER['REMOTE_ADDR']) // nicht eingeloggt...
Falls die IPs allerdings doch gleich sind, muss ich jetzt natürlich in die DB und nachschauen, ob die Session-ID noch aktuell ist.
Wenn da kein Denkfehler drin ist könnte ich mir das IP-Feld in der DB sparen und evt. auch einen Query.
Dann wärs noch wichtig zu entscheiden, ob die Sitzung mit jeder Anfrage verlängert werden soll, dass man bei Aktivität quasi unendlich dran sitzen kann...
Ich hätte jetzt vermutet, dass eine solche Verlängerung mit session_start() automatisch in Kraft tritt? Die Funktion rufe ich ja eh bei jedem geschützten Seitenaufruf auf. Ist dem nicht so?
Nicht, dass man sich wundert, warum plötzlich keine Seite mehr korrekt geladen werden, wenn irgendwo noch "Angemeldet als: " steht.
Ja, das ist auch noch ein interessanter Punkt. Also wenn sich der User selbst aktiv ausloggt, dann kann ich ja den "Angemeldet als"-Bereich mit AJAX austauschen - schließlich löst der User den Logout per Mausklick aus.
Wenn die Session allerdings abläuft, dann tritt das von dir Beschriebene in Kraft. Der User kann zwar nirgends mehr drauf zugreifen, bekommt aber im Loginbereich immer noch den "Angemeldet als: " Text.
Meinst du das so? Mir fällt spontan leider keine Lösung ein. Bräuchte ich zusätzlich noch eine AJAX-Funktion isLoggedIn(), welche ich bei jeder Aktion auslöse und die mir eventuell den "angemeldet als" Text austauscht?
Marscel
2010-05-19, 22:27:17
Also bei Seiten, die geschützt werden sollen, ist das für mich logisch. Aber bei "öffentlichen" Seiten kann ich mir die Geschichte ja sparen, richtig? Sprich nicht einmal session_start() verwenden.
Bei öffentlich Seiten kannst du dir das sparen, ja.
Könnte ich eine Vorüberprüfung machen und wir so eventuell den DB-Query sparen, als auch das IP-Feld in MySQL?
Folgendes vorweg, ich hab nie mit der PHP-eigenen Sessionverwaltung gearbeitet. Ich weiß gar nicht mal, wie die genau funktioniert. Deswegen, unabhängig von DB oder Sessionmanager, du musst dieses Schema einhalten:
- Gibt es eine Session mit der ID, die der User sendet?
- (eigentlich nur zwigend im cookielosen Betrieb nötig, stimmt die IP mit der in der Session überein?)
- Ist die Session noch gültig?
- Wenn alles mit "ja" beantwortet werden kann: User eingeloggt.
- Wenn nicht, also Session ungültig/abgelaufen: User seine ID vergessen lassen, also z.B. Cookie auf "abgelaufen" setzen.
if(!isset($_SESSION['IP']) || $_SESSION['IP'] != $_SERVER['REMOTE_ADDR'])) // nicht eingeloggt...
Ich hoffe, das waren jetzt nur Fehler hier im Hinschreiben.
Wenn da kein Denkfehler drin ist könnte ich mir das IP-Feld in der DB sparen und evt. auch einen Query.
Wenn Schritt 1 damit schon sichergestellt ist, ja, dann geht das.
Ich hätte jetzt vermutet, dass eine solche Verlängerung mit session_start() automatisch in Kraft tritt? Die Funktion rufe ich ja eh bei jedem geschützten Seitenaufruf auf. Ist dem nicht so?
Das weiß ich nicht, kann sein, musst du in die Doku schauen.
Meinst du das so? Mir fällt spontan leider keine Lösung ein. Bräuchte ich zusätzlich noch eine AJAX-Funktion isLoggedIn(), welche ich bei jeder Aktion auslöse und die mir eventuell den "angemeldet als" Text austauscht?
Ja, das ist das, was ich meine. Möglichkeit Eins wäre so eine Funktion wie von dir beschrieben, die würde aber wahrscheinlich jedes Mal einen zweiten Request senden und sonderlich synchronisiert muss das auch nicht sein, nicht schön.
Ich weiß nicht, wie deine Antworten aussehen, ob du einfach HTML zurücksendest, oder das noch in XML verpackst, quasi wie:
<response>
<html>
<![CDATA[<div>Das ist nachgeladener Content.</div>]]>
</html>
</response>
Im Falle von letzterem könnte man nämlich einfach gucken, schickst du ein <response>-Root in der Antwort zurück, würde heißen "Alles Ok, hier hast du den Content". Eine abgelaufene Session, würde dann keinen Inhalt zurückliefern, sondern z.B. das:
<errors>
<error type="invalidSession" />
</errors>
Mit dem AJAX-Response-Callback kannst du dann die Elemente auf ihren Namen untersuchen, und z.B. pauschal sagen, wenn das Root-Element "errors" heißt, dann tu: alert("Es ist ein Fehler passiert."). Kannst du natürlich auch verfeinern, indem du schaust, ist das vom type eine ungültige Session und den User damit auffordern, sich wieder anzumelden.
mittelding
2010-05-20, 20:08:43
Ich weiß nicht, wie deine Antworten aussehen, ob du einfach HTML zurücksendest, oder das noch in XML verpackst, quasi wie:
<response>
<html>
<![CDATA[<div>Das ist nachgeladener Content.</div>]]>
</html>
</response>
Danke, so mach ichs jetzt. Hatte die Idee schon früher, wusste aber erst nicht, wie ich HTML in XML verpacken kann ohne dass es knallt. Bin dann ebenfalls auf CDATA gestoßen, was mich jedoch abgeschreckt hat: dort darf nichts drinstehen, was in XML auch nicht erlaubt ist.
Könnte das irgendwelche Probleme machen mit HTML?
Marscel
2010-05-20, 20:32:16
Danke, so mach ichs jetzt. Hatte die Idee schon früher, wusste aber erst nicht, wie ich HTML in XML verpacken kann ohne dass es knallt. Bin dann ebenfalls auf CDATA gestoßen, was mich jedoch abgeschreckt hat: dort darf nichts drinstehen, was in XML auch nicht erlaubt ist.
Könnte das irgendwelche Probleme machen mit HTML?
Wüsste ich nicht, CDATA heißt ja eigentlich character data, sollten keine Auswirkung auf das DOM besitzenden XML-Dokument haben - wenn doch, stimmt irgendwas nicht.
Das Script, das das XML ausgibt, sollte den Content-Type im HTTP-Response-Header auf text/xml setzen und es sollte noch ein XML-Kopf dabei sein.
Wenn du noch Javascript nachladen willst, Klassen oder so, musst du das JS noch durch den Evaluator jagen. Aber das sollte alle kleinen Stolperfallen gewesen sein.
AlecWhite
2010-05-21, 02:34:31
Mit CDATA geht das schon....allerdings wird der IE bei eventuell nachgeladenen JS streiken - die Sicherheitspolicy beim IE besagt, dass keine nachgeladenen JS ausgeführt werden (um XSS Attacken zu verhindern)
Das führt mich zur Frage: Wie sicher soll das gesamte System sein bzw. gegen wen willst du verteidigen? Alles was du bislang machst, dürfte im Zweifelsfall nicht wirklich als sicher betrachtet werden....
Marscel
2010-05-21, 19:45:01
Mit CDATA geht das schon....allerdings wird der IE bei eventuell nachgeladenen JS streiken - die Sicherheitspolicy beim IE besagt, dass keine nachgeladenen JS ausgeführt werden (um XSS Attacken zu verhindern)
Ich bin mir ziemlich sicher, dass der IE auch eval() unterstützt, das man mit einem String beliebiger Herkunft befüllen kann.
Das führt mich zur Frage: Wie sicher soll das gesamte System sein bzw. gegen wen willst du verteidigen? Alles was du bislang machst, dürfte im Zweifelsfall nicht wirklich als sicher betrachtet werden....
Was soll für wen wann unsicher - im Zweifelsfall - sein?
Demirug
2010-05-21, 20:05:05
Ich bin mir ziemlich sicher, dass der IE auch eval() unterstützt, das man mit einem String beliebiger Herkunft befüllen kann.
Wenn er es nicht könnte wären wir ziemlich aufgeschmissen. Allerdings benutzten wir eval nur zum JSON parsen wenn kein nativer JSON Support verfügbar ist.
Scripts injecten wir durch hinzufügen von Skript tags ins Dokument. Allerdings nur in der Debug Version. Die final Version besteht aus einem großen JS File.
vBulletin®, Copyright ©2000-2025, Jelsoft Enterprises Ltd.