Nun habe ich mich ja in letzter Zeit neben CakePHP auch mit dem jQuery-Framework beschäftigt, und in diesem Zusammenhang eine kleine “Probeanwendung” gebaut, nämlich eine Login-Seite mit Ajax-Funktionalität. Für den ein oder anderen stellt sich nun sicherlich die Frage, ob solch eine Funktion wirklich sinnvoll ist…doch für mich zählt hier eher die Erklärung als der Sinn des Ganzen :-).
Wie das Ganze später aussehen könnte seht ihr in dieser kurzen Demo (richtiger Login: gast:gast). Das ganze wurde grafisch natürlich ein wenig aufgepeppt. Um die jQuery-Animationen auf dem variablen Hintergrund hinzubekommen musste auf das PNG-Format zurückgegriffen werden, zudem wurde für die IE6-User ein PNG-Behaviour eingesetzt.
Nun aber Butter bei die Fische.
Was das XHTML angeht bleibt eigentlich alles beim alten, denn gerade das ist ja das Positive an jQuery: Man braucht den (X)HTML-Quelltext nicht wirklich anzufassen.
Daher hier erstmal das komplette Javascript:
jquery-script.js
$(document).ready(function(){
$("#login").Bounce(70);
$("#footbar").slideDown("slow");
$("input").focus(function(){
$(this).parent().addClass("active");
});
$("input").blur(function(){
$(this).parent().removeClass();
});
$('#login form').submit(function(e){
e.preventDefault();
var username = $("#username input").attr('value');
var password = $("#password input").attr('value');
$.ajax({
type: "POST",
timeout: 7000,
data: {username: username, password: password},
url: "login",
success: function(result) {
if(result != "true") {
$("#ajax_load").animate({opacity: 1.0}, 500).fadeOut(500);
$("#messages").append('<div id="ajax_error">Anmeldung war nicht erfolgreich!</div>');
$("#login").Shake(4);
}
else {
$("#ajax_load").fadeOut(200);
$("#messages").append('<div id="ajax_accept">Erfolgreich, sende an System...</div>');
$("#ajax_accept").hide().show("slow",function(){
setTimeout(function(){$("#login").slideUp(500);},500);
setTimeout(function(){$('#login form')[0].submit();},1200);
});
}
}
})
});
$(".button")
.ajaxStart(function(){
$("#messages div").remove();
$("#messages").append('<div id="ajax_load">Überprüfe Daten...</div>');
});
});
Ok, also was wird hier gemacht?
$(document).ready(function(){...});
Wartet erst einmal bis der DOM fertig/bereit ist.
$("#login").Bounce(70);
Ist eine Funktion des Interface-Plugins für jQuery und sorgt dafür, das das Element mit der CSS-ID “login” beim Start der Seite um 70 Pixel springt.
$("#footbar").slideDown("slow");
Ebenfalls eine Animation, nur das diese bewirkt das die Fußzeile #footbar beim Start der Seite langsam hereingleitet.
$("input").focus(function(){
$(this).parent().addClass("active");
});
$("input").blur(function(){
$(this).parent().removeClass();
});
Sobald ein Input-Feld auf der Seite aktiviert wird (focus), bekommt dessen Eltern-Element (in diesem Fall das übergeordnete <label> die Klasse active zugewiesen. Wird das Feld wieder verlassen (blur), so wird auch die Klasse wieder entfernt. Diese Funktion dient also einfach nur zur optischen Hervorhebung des aktiven Input-Feldes.
$('#login form').submit(function(e){
e.preventDefault();
var username = $("#username input").attr('value');
var password = $("#password input").attr('value');
Jetzt wirds spannend. Diese Codezeilen werden nur dann ausgefüllt, wenn das Formular(form) innerhalb der CSS-ID “#login” abgesendet (submit) wurde. In unserem Fall wird eine Funktion e gestartet. e.preventDefault(); verhindert dabei zunächst, das das Formular einfach über den Browser abgesendet wird, denn wir wollen ja eine Ajax-Anfrage starten. var username = $("#username input").attr('value'); und var password = $("#password input").attr('value'); legen uns zwei Variablen mit den derzeitigen Inhalten (value-Attribut) der Input-Felder in der CSS-ID “username” und “password” an. Ich denke bis hierhin alles relativ logisch.
$.ajax({
type: "POST",
timeout: 7000,
data: {username: username, password: password},
url: "login",
success: function(result) {...}
Dieser Teil beginnt eine Ajax-Abfrage. Über type: "Post" definieren wir, das es sich hierbei um eine Post-Anfrage handelt. Warum gerade Post? Nun, würden wir eine GET-Anfrage machen, so müssten wir den Benutzernamen und das Passwort in der URL übertragen, also seeeehr unsicher, daher an dieser Stelle eine POST-Anfrage.
timeout: 7000, besagt das die Anfrage nach 7 Sekunden ohne Ergebnis als fehlerhaft abbrechen würde.
data: {username: username, password: password} steckt unsere vorher angelegten Variablen für die beiden Formular-Felder in die POST-Daten für die Ajax-Anfrage, die wir dann später mit PHP bzw. CakePHP auslesen und überprüfen können.
url: "login" gibt einfach an, an welche URL die Daten überhaupt gesendet werden, hier könnte z.B. auch “check.php” stehen.
success: function(result) {...} ist der Code-Abschnitt, der bei einer erfolgreichen Ajax-Abfrage ausgeführt wird (was noch nicht heißt das die eingegebenen Formularwerte richtig waren).
if(result != "true") {...}
Dieser Textabschnitt wird ausgeführt, sobald die Ajax-Anfrage erfolgreich abgeschlossen wurde, und der Inhalt der ausgelieferten Datei nicht gleich true ist, sprich, sobald wir vom PHP-Script die Antwort bekommen haben, das die Logindaten nicht korrekt waren.
$("#ajax_load").animate({opacity: 1.0}, 500).fadeOut(500);
$("#messages").append('<div id="ajax_error">Anmeldung war nicht erfolgreich!</div>');
$("#login").Shake(4);
In diesem Fall wollen wir das dem User natürlich auch ausgeben. Dafür wird nach einer Wartezeit von 500 Millisekunden div mit der CSS-ID “messages” mit dem HTML-Code <div id="ajax_error">Anmeldung war nicht erfolgreich!</div> gefüllt. Zu guter letzt wird das #login-Fenster über Shake(4) viermal hin und her gewackelt, um ein Kopfschütteln zu simulieren.
else {
$("#ajax_load").fadeOut(200);
$("#messages").append('<div id="ajax_accept">Erfolgreich, sende an System...</div>');
$("#ajax_accept").hide().show("slow",function(){
setTimeout(function(){$("#login").slideUp(500);},500);
setTimeout(function(){$('#login form')[0].submit();},1200);
});
}
Dieser Codeabschnitt wird ausgeführt, wenn vom Server eine andere Antwort als “false” kommt, also wenn die Logindaten korrekt waren. Dafür wird erstmal die Ladeanzeige #ajax_load (dazu später mehr) ausgeblendet und dem uns bereits bekannten #messages-div eine positive Meldung eingeworfen und über show() langsam eingefadet. setTimeout dient uns in diesem Beispiel übrigens dazu, ein Script zeitlich ein wenig zu steuern, da ansonsten die Animationen zu schnell ablaufen würden, und der Benutzer von den Ausgaben evtl. nichts mitbekommen würde.
Zum Ende hin wird das komplette Loginfeld durch slideUP("500"); vertikal zusammengerollt, und das Formular durch $('#login form')[0].submit(); auf dem ganz normalem Weg an den Server abgeschickt, denn durch die [0] vor der submit-Anweisung hebeln wir das vorher gesetzt e.PreventDefault() aus.
$(".button")
.ajaxStart(function(){
$("#messages div").remove();
$("#messages").append('<div id="ajax_load">Überprüfe Daten...</div>');
});
Bewirkt zudem noch, das sobald unser Formular über Ajax abgefeuert wurde, alle Nachrichten im #messages-Container gelöscht werden, und im Anschluss dort eine Ladeanimation eingepackt wird.
So, das war es soweit mit dem jQuery-Code, vielleicht für den Anfänger etwas verwirrend, aber das liegt vielleicht auch an meinem evtl. nicht ganz optimalem Quellcode.
Prüfen der Daten mit CakePHP
Nun müssen wir ja auf der Serverseite die Ajaxanfrage auch prüfen und natürlich ein Ergebnis ausliefern. Mit CakePHP geht das relativ einfach, da man hiermit leicht zwischen einer normalen Browseranfrage und einer Ajax-Anfrage unterscheiden kann, man kann also beide Anfragen über ein und die selbe URL laufen lassen.
function login() {
$this->layout = 'login';
if($this->RequestHandler->isAjax() == true) {
$result = $this->User->find(array('username' => $_POST['username'],'password' => md5($_POST['password'])));
if(!empty($result)) { echo "true"; } else { echo "false"; }
$this->render(null,'ajax');exit;
}
if(!empty($this->data)) {
$result = $this->User->find(array('username' => $this->data['User']['username'],'password' => md5($this->data['User']['password'])));
if(!empty($result)) {
$this->Session->write('User', $result['User']['id']);
$this->redirect('/'.CAKE_ADMIN.'/pages/');
} else {
$this->flash('Falsche Logindaten','/'.CAKE_ADMIN.'/users/login');
}
}
Hierfür habe ich meinem User-Controller eine neue Action mit dem Namen login verpasst.
Der obere Quelltext ließt sich mit Cake gewohnt einfach. In Kurform wähle ich am Anfang des Scripts das Login-Layout aus und frage ab, ob der derzeitige Request denn eine Ajax-Anfrage ist. Danach Suche ich in der Datenbank nach dem passenden Einträgen und gebe das Ergebnis über $this->render(null,'ajax');exit; als simplen Quelltext aus, also ohne Template drumherum.
Ist es keine Ajax-Abfrage, so passiert im Prinzip genau das selbe (denn nur auf die Ajax-Abfrage können wir uns ja nicht verlassen). Allerdings wird in diesem Fall natürlich auch eine Session erzeugt, damit der User fortan auch eingeloggt bleibt.
Übrigens hat mir beim erstellen der Mini-Anwendung das Visitenkarten-Tutorial von Silvan Hagen sehr geholfen, sehr gut geschrieben und leicht zu verstehen. Die Inspiration für den Loginscreen kam von Frank Weinerth.
Kommentare zum Thema Ajax-Login mit jQuery und CakePHP:
Genial! Danke für das Tutorial, hat mir echt weitergeholfen. Das Design ist dir gut gelungen!
Also habe soweit alles gemacht.
Nur klappt das ganze noch nicht mit cakePHP.
und zwar nehme ich an das es an der url liegt.
meine controller fkt heisst: /index/login
in der jquery-login.js
url: “/index/login”
und in der thtml
<form method=“post” action=”<? echo $html->url(’/index/login’); ?>”>
was koennte hier falsch sein?
im controller (/index/login)
if (!empty ($this->data)) {
if($this->data[‘User’][‘username’] == ‘asdf’ && $this->data[‘User’][‘password’] == ‘asdf’)
$this->redirect(’/index/admin’);
else
$this->redirect(’/index/start’);
Hallo Christian könntest Du bitte das Demo zum Download freigeben?
Ich versuche das Zusammenspiel zwischen html,javascript, php usw. zu begreifen.
Vielen Dank
Hi,
kannst Du bitte den Quellcode zum download bereitstellen ?
Ich bin newbie bei ajax und jquery und würde diese login gerne verstehen.
Danke
Andreas
Mhm, ich verstehs grad nich ganz :) Die JS-Dateien, CSS-Dateien und Grafiken können doch aus dem Beispiel bezogen werden? Den kompletten JS-Code sieht man doch zudem auch oben mit super Erklärung?
Was ich eben einfach vermeiden will ist, das hier jemand den Code unverändert übernehmen will, denn das ist kein Plugin oder dergleichen, sondern eben einfach ein Praxisbeispiel, daher ist nachbauen gerne erwünscht, aber nicht unverändertes Übernehmen :)
Wer jQuery lernen will sollte gerade am Anfang nicht mit einem fertigen Baustein anfangen, sondern natürlich auch verstehen was da überhaupt steht, oder?
Mein Problem ist das ich nicht genau weiß wie die view
aussehen muss …
Die Demo scheint ja leider auch nicht mit cake gemacht zu sein, sondern einfach
php oder ?
Hallo,
habe gerade diesen Beitrag gelesen. Kann man diese Lösung mit reinem php erstellen?
Hast Du eventuell ein Bsp. Vielen Dank!
Hi,
ich habe eine Frage zu der Javascript login. wie siehst mit der Session aus und wieso gibt da keine redirect auf eine neue seite? Ich habe das Problem, dass die Login Seite weiter angezeigt wird und nichts passiert. Was habe ich denn falsch gemacht?
Hallo, erst ein mal danke für so ein super Tutorial.
Nun hab ich eine Frage, hoffentlich liest Du diese denn noch nach 1 1/2 Jahren.
Ich nutze Firefox 3 und SecureLogin als Addon. Wenn ich mich jetzt auf der Demo Seite mit willkürlichen username und passwort anmelden mag geht das klar nicht. Speicher ich diese aber in SecureLogin ab und drücke dann die Tastenkombination ‘alt+n’ habe ich auf ein mal Zugang zu deiner ‘test’ Seite.
Woran könnte das liegen? Habe versucht den Fehler zu finden. Erfolglos.
sehr interessante sache! arbeite selbst auch viel mit jquery, jedoch mehr im grafischen stil, gute arbeit! freue mich auf mehr :)
weiter so!
Guten Abend! :-)
Mir gefällt das Design deines Logins! Darf man dieses kopieren? (Ich beziehe mich auf die Grafiken und CSS.) Und wenn ich schon dabei bin – wie steht es um die PSD der Header-Grafik? :-P
Grüße und ein schönes Wochenende,
Martin
Hi
Nichts für ungut, aber das Skript ist überhaupt nicht sicher. Das kann jedes Kind “hacken”. Man nehme Firebug (Plugin für Firefox) und setze auf der Demo-Seite bei folgender Zeile einen Haltepunkt:
if(result != “false”) {
dann kann man einfach die Variable result auf true setzen und schon ist man drin :P
Freue mich schon auf ein sicheres Skript^^
Chris
Absolut korrekt. Dem ist wohl nichts hinzuzufügen…
@chris: warum sollte das skript nicht sicher sein? was bringt mir es wenn ich jquery(bzw. javascript) aushebel aber serverseitig keine session angelegt wird für den user und damit das acl/auth component den user spätestens wenn er auf die weiterleitung klickt wieder auf die loginseite schickt ?!
jquery und das ganze web 2.0 ist mehr oder weniger nur ein komfortgeschichte für nutzer. stichwort pagereload etc. pp
Hallo,
da ich phpcake nicht verwende wollte ich es wie folgt versuchen:
$getUser_sql = $db->select(‘SELECT * FROM `’ . USERS_TABLE_NAME . ‘` WHERE username=”’. $_POST[‘username’] . ‘” AND password = “’ . $_POST[‘password’] . ‘”’); $getUser = mysql_query($getUser_sql); $getUser_result = mysql_fetch_assoc($getUser); $getUser_RecordCount = mysql_num_rows($getUser);
if($getUser_RecordCount < 1){ echo ‘false’;} else { echo ‘true’;}nur funktioniert das nicht. Da ajax die POST (username und passwort) an php nicht übergibt.
wie geht das ohne phpcake?
Kommentar-Feed für diesen Artikel
Site of the Month bei textpattern resources [ge] Ganz vergessen: Grafzahl bei Twitter


wie sieht es mit der sicherheit hier aus?