‫Kursleiter: In dieser
‫Vorlesung werden wir also die Passwörter unserer Benutzer in der Datenbank verwalten.
‫Und damit meine ich, zuerst zu
‫überprüfen, ob das eingegebene Passwort mit dem bestätigten Passwort übereinstimmt und
‫dann auch das Passwort in der Datenbank zu verschlüsseln, um
‫es vor Angriffen zu schützen.
‫Das erste, was wir tun
‫werden, ist zu überprüfen, ob die beiden eingegebenen Passwörter gleich sind.
‫Und das geht am
‫besten hier in der Passwortbestätigung, okay?
‫Also schreiben wir unseren benutzerdefinierten Validator dafür, in Ordnung?
‫Denken Sie also daran, wir verwenden die Eigenschaft validieren
‫und dann, da wir eine Funktion
‫und auch eine Fehlermeldung erstellen möchten, öffnen wir hier ein neues Objekt
‫und erstellen dann dort einen Validator, der
‫die Funktion sein wird
‫und fangen wir tatsächlich mit diesem an.
‫Denken Sie also daran, dass wir hier
‫nur eine einfache Callback-Funktion angeben müssen, die dann aufgerufen wird,
‫wenn das neue Dokument erstellt wird.
‫Also, function,
‫und auch hier können wir keine Pfeilfunktion verwenden,
‫weil wir tatsächlich das disk-Schlüsselwort verwenden müssen.
‫Okay?
‫Denken Sie also daran, dass wir von
‫der Validierungsfunktion entweder true oder
‫false zurückgeben und wenn der Rückgabewert
‫false ist, bedeutet dies, dass wir einen Validierungsfehler erhalten, okay?
‫Und natürlich, wenn es stimmt, dann nicht.
‫Was wir hier also wollen, ist zu sagen, dass das
‫aktuelle Element, also password Confirm, diesem Punkt-Passwort entspricht, also
‫Passwort Confirm, diesem Punkt-Passwort entspricht, und das
‫ist es tatsächlich!
‫Wenn also zum Beispiel die Passwortbestätigung A-B-C ist und
‫das Passwort auch A-B-C ist, dann wird
‫dies natürlich true zurückgeben, in Ordnung?
‫Und so wird die Validierung
‫bestanden und es wird kein Fehler auftreten.
‫Aber wenn das anfängliche Passwort, sagen wir, X-Y-Z ist,
‫dann wird dies natürlich false
‫zurückgeben und wir haben einen Validierungsfehler, okay?
‫Also, ganz einfach, aber wir müssen
‫bedenken, dass das nur beim Speichern funktioniert, okay?
‫Darüber habe ich also schon
‫einmal gesprochen, als wir den benutzerdefinierten Validator für das Tourmodell verwendet haben, oder?
‫Aber ich erinnere Sie hier
‫noch einmal daran, weil dies hier in diesem Punkt absolut entscheidend ist, okay?
‫Also lassen Sie es mich hier für Sie aufschreiben.
‫(Tastaturklick) Beim
‫Speichern.
‫Okay?
‫Und aus diesem Grund müssen wir immer dann, wenn wir
‫einen Benutzer aktualisieren möchten, immer auch speichern und
‫nicht zum Beispiel einen finden und aktualisieren, wie wir
‫es bei unseren Touren getan haben, okay?
‫Denken wir also daran, wenn
‫wir den Rest des Codes für den Rest des
‫Abschnitts und insbesondere für die Aktualisierung schreiben, okay?
‫Denn sagen wir, wir haben das Passwort des Benutzers
‫einfach mit einem regelmäßigen Update aktualisiert.
‫Dann würde diese Passwortbestätigung, die wir hier
‫haben, in diesem Fall nicht mehr funktionieren, okay?
‫Und das kann natürlich nicht passieren, okay?
‫Denken Sie also daran, dass dies nur funktioniert, wenn
‫wir ein neues Objekt erstellen, also bei Punkterstellung oder beim Speichern.
‫Okay?
‫Also, beim Erstellen und
‫Speichern, Also beim Erstellen und Speichern, In
‫Ordnung?
‫Also erstellen wir ein neues Objekt mit create, richtig?
‫Also, genau hier, habe eine Punkterstellung verwendet Also,
‫genau hier, habe eine Punkterstellung
‫verwendet, aber erinnere
‫mich, wie ich Ihnen auch gezeigt habe, dass
‫wir einen Benutzer-Punktspeicher verwenden können, richtig?
‫Und tatsächlich können wir auch einen Benutzerpunktspeicher verwenden,
‫um den Benutzer zu aktualisieren, in Ordnung?
‫Aber dazu später noch einmal mehr.
‫Okay?
‫Lassen Sie uns diese Validierung jetzt also hier ausprobieren, okay?
‫Versuchen wir also zunächst einmal, einen
‫neuen Benutzer mit diesen Daten
‫hier anzulegen, was nicht funktionieren sollte, da wir
‫bereits einen Benutzer mit dieser E-Mail-Adresse haben und wir sagten,
‫dass dieser eindeutig sein sollte und daher
‫nicht funktionieren sollte.
‫Okay, und natürlich unser Fehler mit doppeltem Schlüssel, oder?
‫Wenn Sie jetzt in der Produktion
‫wären, würden wir natürlich schon unseren schön formatierten Fehler bekommen,
‫den wir im letzten Abschnitt erstellt haben, oder?
‫Aber im Moment befinden wir uns in der Entwicklung und das ist der Fehler, den wir
‫definiert haben, den wir sehen wollen.
‫Okay?
‫Lassen Sie uns hier einfach eine andere E-Mail
‫verwenden und da wir hier an
‫der E-Mail arbeiten, sehen wir uns auch an, wie die E-Mail-Adressvalidierung funktioniert.
‫Nehmen wir an, wir haben dies als unsere E-Mail-Adresse angegeben.
‫Daher sehen wir den Fehler "Bitte geben Sie eine gültige E-Mail an. " Okay?
‫Testen wir es also einfach so, weil ich denke, dass
‫dies auch nicht gültig sein sollte.
‫Vielleicht ist es das, aber mal sehen.
‫Und ja, eigentlich liegt es
‫nicht daran, dass es keine Domainnamen mit nur einem Buchstaben gibt, okay?
‫Dieser Validator ist also ziemlich spezifisch,
‫also wirklich gut.
‫Wenn wir es jetzt so machen, dann sollte es natürlich funktionieren.
‫Aber egal, was wir
‫hier testen wollten, sind diese verschiedenen Passwörter, okay?
‫Und ich erinnere mich
‫jetzt, dass wir eigentlich keine Fehlermeldung erstellt haben, glaube ich.
‫Und ja, wir haben es nicht getan.
‫Und so fügen wir das auch hier hinzu.
‫Also Nachricht,
‫sind nicht die
‫gleichen.
‫Okay.
‫Also lasst uns hier etwas hinzufügen, egal.
‫Passwörter sind also nicht gleich Passwörter, okay?
‫So perfekt.
‫Und jetzt sollte natürlich unsere Validierung bestanden sein.
‫Und tatsächlich ist es so und wir haben unseren neuen Benutzer erstellt.
‫Lassen Sie uns hier zu
‫Compass gehen, einen Blick darauf werfen und ihn
‫dann tatsächlich löschen, damit ich später weitere Benutzer mit derselben E-Mail erstellen kann.
‫Gut?
‫Und diesen ganzen Kram wollen wir
‫sowieso nicht hier haben, also all diese Testbenutzer, okay?
‫Aber jetzt besteht der nächste Schritt darin, diese einfachen
‫Passwörter, die wir gerade in unserer
‫Datenbank speichern, tatsächlich zu verschlüsseln.
‫Wie ich im letzten Video erwähnt
‫habe, ist es bei
‫der Arbeit mit Authentifizierung eines
‫der grundlegendsten Prinzipien, niemals einfache Passwörter in einer Datenbank zu speichern, okay?
‫Das ist also absolut nicht akzeptabel, okay?
‫Wir sollten also wirklich immer die Passwörter der Benutzer verschlüsseln, denn stellen
‫Sie sich vor, dass ein
‫Hacker aus irgendeinem Grund Zugriff auf die Datenbank erhält.
‫Wenn dann dort die Passwörter im Klartext hinterlegt sind, dann kann
‫er sich einfach als beliebiger Benutzer einloggen
‫und dann machen was er
‫wirklich will und unter Umständen viel Schaden anrichten, okay?
‫Und das müssen wir unbedingt verhindern.
‫Und so lassen Sie uns jetzt vorangehen und dies implementieren.
‫Wo macht man das nun eigentlich am besten?
‫Nun, ich würde argumentieren, dass das Modell immer der beste
‫Ort für diese Art von Funktionalität ist.
‫Also in diesem Fall die Verschlüsselung,
‫weil sie wirklich mit den Daten selbst zu tun
‫hat und sie daher am
‫Modell und nicht am Controller liegen sollte, okay?
‫Behalten Sie auch hier die Philosophie der dicken Modelle
‫und der dünnen Controller im Hinterkopf.
‫Gut?
‫Wie werden wir nun diese Verschlüsselung implementieren?
‫Nun, dies ist ein weiterer perfekter Anwendungsfall
‫für die Verwendung von Mongoose-Middleware.
‫Und die, die
‫wir verwenden werden, ist eine Pre-Save-Middleware.
‫Also im Grunde Dokument-Middleware, okay?
‫Denken Sie also daran, dass wir das im Schema definiert haben, okay?
‫Und in diesem Fall wollen wir einen
‫Pre-Hook setzen, also eine Pre-Middleware auf Save, in Ordnung?
‫Also eine Pre-Middleware beim Speichern, in Ordnung?
‫Und der Grund, warum wir das
‫so machen, ist, dass
‫die Middleware-Funktion, die wir hier spezifizieren werden, also die
‫Verschlüsselung, zwischen dem Moment, in dem wir
‫diese Daten erhalten, und dem Moment, in
‫dem sie tatsächlich auf dem gespeichert werden, stattfindet Datenbank, okay?
‫Hier läuft also die Pre-Save-Middleware.
‫Zwischen dem Abrufen der Daten und dem Speichern in der Datenbank.
‫Das ist also der perfekte Zeitpunkt, um die Daten zu manipulieren.
‫Gut?
‫Also, eine
‫Funktion, und dann denken Sie daran, dass wir Zugriff
‫auf die nächste Funktion haben, um die nächste Middleware aufzurufen.
‫Okay, jetzt wollen wir das Passwort eigentlich
‫nur verschlüsseln, wenn das Passwort-Feld auch tatsächlich aktualisiert wurde, okay?
‫Also im Grunde nur, wenn das Passwort wirklich geändert oder
‫auch neu erstellt wird, in Ordnung?
‫Denn stellen Sie sich vor, der Benutzer aktualisiert nur die E-Mail.
‫Dann wollen wir
‫das Passwort dann natürlich nicht noch einmal verschlüsseln, oder?
‫Und so können wir das mit Mongoose tun.
‫Und so werden wir sagen, wenn und dann dies, das
‫sich auf das aktuelle Dokument bezieht, richtig?
‫Und so wird in diesem Fall der aktuelle
‫Benutzer und dann geändert.
‫Okay?
‫Wir haben also eine Methode für alle Dokumente, die wir
‫verwenden können, wenn ein bestimmtes Feld geändert wurde.
‫Hier müssen wir also den Namen des Felds eingeben,
‫also "Passwort. " Okay?
‫Im Grunde wollen wir hier also
‫sagen, dass, wenn das Passwort nicht geändert wurde, in
‫diesem Fall einfach von dieser Funktion zurückkehren und
‫keinen anderen Code ausführen, der hier enthalten
‫ist, und dann aufrufen
‫die nächste Middleware.
‫Okay?
‫Wenn das Passwort also nicht geändert wurde, verlassen wir
‫diese Funktion einfach und
‫rufen die nächste Middleware auf.
‫Andernfalls führen wir dann den Code aus,
‫den ich hier einfügen werde.
‫Und jetzt ist es endlich an der Zeit, das
‫Passwort tatsächlich zu verschlüsseln, oder wie wir auch sagen können, das Passwort zu hashen, okay?
‫Sie werden also ständig den Begriff "Hash" oder
‫"Hashing" sehen und das bedeutet im Grunde auch Verschlüsselung, okay?
‫Jetzt werden wir diese Verschlüsselung oder Hashing
‫mit einem sehr bekannten und
‫gut untersuchten und sehr beliebten Hashing-Algorithmus namens bcrypt durchführen.
‫Okay?
‫Dieser Algorithmus wird also zuerst unser Passwort salzen und dann hashen,
‫um es wirklich stark zu machen, um es
‫vor Bruteforce-Angriffen zu schützen, in Ordnung?
‫Aus diesem Grund
‫muss die Verschlüsselung wirklich stark sein.
‫Denn Bruteforce-Angriffe könnten versuchen, ein bestimmtes
‫Passwort zu erraten, wenn es nicht wirklich stark verschlüsselt ist.
‫Und denken Sie daran, wie ich sagte, dass bcrypt unser
‫Passwort salzt und das bedeutet nur, dass es
‫dem Passwort eine zufällige Zeichenfolge hinzufügt, damit zwei gleiche
‫Passwörter nicht denselben Hash generieren, okay?
‫Sinn ergeben?
‫Ich werde jetzt nicht auf alle kryptografischen Details eingehen, wie
‫das wirklich hinter den Kulissen funktioniert
‫und warum wir ein so komplexes System brauchen, okay?
‫Aber natürlich können Sie online alles über bcrypt lesen.
‫Da gibt es wirklich viel
‫Interessantes zu entdecken, oder?
‫Wie auch immer, lassen Sie uns jetzt fortfahren und das bcrypt
‫js-Paket verwenden, um diesen Algorithmus zu verwenden.
‫Also, also
‫npm install,
‫also npm install
‫bcryptjs.
‫Okay?
‫Dies ist im Grunde eine bcrypt-Implementierung
‫für Javascript.
‫Okay?
‫Gehen wir zurück zu unserem Hauptterminal
‫und importieren Sie es hier.
‫Und dieser heißt standardmäßig nur bcrypt, okay?
‫Und nicht bcryptjs.
‫(Tastaturklick) Alles klar.
‫Gut.
‫Und jetzt verwenden wir es tatsächlich.
‫Wir möchten also sagen, dass dieses Punkt-Passwort, also
‫das aktuelle Passwort in diesem
‫Dokument, gleich bcrypt-Punkt-Hash sein sollte, sollte
‫gleich bcrypt-Punkt-Hash sein und dann unser
‫aktuelles Passwort.
‫Okay?
‫Und dann müssen wir hier einen Kostenparameter angeben, okay?
‫Und wir könnten dies tatsächlich auf zwei Arten tun.
‫Der erste Weg besteht also darin, den Salt manuell zu
‫generieren, so dass im Grunde eine
‫zufällige Zeichenfolge zu unserem Passwort
‫hinzugefügt wird, und dann diesen Salt hier in dieser Hash-Funktion zu verwenden.
‫Gut?
‫Aber der Einfachheit halber können
‫wir hier auch einfach einen Kostenparameter an
‫diese Funktion übergeben.
‫Und das ist im Grunde
‫ein Maß dafür, wie CPU-intensiv dieser Vorgang sein wird, in Ordnung?
‫Und der Standardwert hier ist meiner Meinung nach 10,
‫aber im Moment ist es etwas besser, 12 zu
‫verwenden, weil Computer immer leistungsfähiger geworden sind.
‫Wie vor 20 Jahren hätten Sie hier und dann
‫acht verwenden können, etwas später als
‫10, aber im Moment ist es am besten, 12 zu verwenden.
‫Und je höher diese
‫Kosten hier sind, desto CPU-intensiver wird der
‫Prozess und desto besser wird das Passwort verschlüsselt, okay?
‫Und natürlich könnten wir noch höher
‫gehen, aber dann würde es viel zu lange dauern, okay?
‫Und das werde ich Ihnen gleich zeigen.
‫Okay?
‫Aber lassen Sie uns
‫das jetzt tatsächlich beenden, denn hier ist noch etwas übrig.
‫Dieser Hash hier ist also eigentlich die asynchrone Version,
‫aber es gibt auch eine synchrone Version.
‫Aber wie Sie bereits wissen, möchten wir die
‫synchrone Version nicht
‫verwenden, da dies die Ereignisschleife blockiert und dann andere Benutzer
‫daran hindert, die Anwendung zu verwenden.
‫So wie wir es am Anfang gelernt haben.
‫Und so möchten wir
‫natürlich die asynchrone Version verwenden, die diese ist.
‫Und dies wird dann ein
‫Versprechen zurückgeben und dieses Versprechen müssen wir natürlich abwarten.
‫Also müssen wir wait verwenden und dann sagen, dass diese
‫Funktion eine asynchrone Funktion ist, genau so.
‫Lassen Sie uns das hier noch einmal zusammenfassen.
‫Wir möchten unser aktuelles Passwort also grundsätzlich
‫so einrichten, dass diese Version des ursprünglichen Passworts mit Kosten von 12
‫verschlüsselt wird, das Passwort nicht
‫zu leicht knackt werden kann, aber auch nicht, dass die
‫Anwendung zum Verschlüsseln des Passworts zu lange dauert. OK?
‫Damit haben wir also unser Passwort
‫verschlüsselt und jetzt am Ende
‫müssen wir im Grunde genommen das Bestätigungspasswort löschen, in Ordnung?
‫Denn zu diesem Zeitpunkt
‫haben wir nur das echte Passwort gehasht, oder?
‫Also, diese Punkt-Passwortbestätigung, Also, diese
‫Punkt-Passwortbestätigung, und
‫wie wir das Feld grundsätzlich löschen,
‫damit es nicht in der Datenbank beibehalten
‫wird, ist es auf undefiniert zu setzen.
‫Gut?
‫Wir brauchen diese Passwortbestätigung hier also wirklich nur für
‫die Validierung, die wir zuvor implementiert haben.
‫Also nur um sicherzustellen,
‫dass der Benutzer tatsächlich zwei gleiche Passwörter
‫eingegeben hat, damit er keine Fehler mit seinem Passwort macht.
‫Richtig?
‫Nachdem diese Validierung erfolgreich war, benötigen
‫wir dieses Feld tatsächlich nicht mehr, sodass
‫wir es wirklich nicht in der Datenbank speichern möchten.
‫Und deshalb setzen wir es hier einfach auf undefiniert.
‫Gut?
‫Jetzt fragen Sie sich vielleicht, warum
‫das funktioniert, weil wir die Passwortbestätigung tatsächlich auf
‫erforderlich gesetzt haben, oder?
‫Aber das bedeutet einfach, dass es eine erforderliche Eingabe
‫ist und nicht, dass sie tatsächlich in der Datenbank
‫gespeichert werden muss, okay?
‫zur Datenbank, okay?
‫Zum Abschluss müssen wir natürlich noch als nächstes anrufen.
‫Okay?
‫Lassen Sie es uns sparen.
‫Und eigentlich werde ich hier einige Kommentare
‫hinzufügen, um es für Sie wirklich klar zu machen.
‫Im Grunde wird diese Funktion also nur
‫ausgeführt,
‫wenn das
‫Kennwort tatsächlich geändert wurde.
‫Dann
‫Hash hier das Passwort mit Kosten von 12.
‫Löschen Sie
‫dann das Feld zur Kennwortbestätigung.
‫Okay.
‫Und jetzt lassen Sie uns das testen.
‫Und ich werde jetzt mit genau diesen Daten einen neuen Benutzer anlegen
‫und schauen wir uns nun das Ergebnis an.
‫Und tatsächlich erhalten wir jetzt dieses sehr seltsam aussehende Passwort,
‫das tatsächlich die verschlüsselte Version von pass1234 ist.
‫Und auch, wie Sie sehen, ist die Passwortbestätigung nicht mehr vorhanden.
‫Okay?
‫Und so haben wir jetzt Benutzer auf
‫sichere Weise in unserer Datenbank gespeichert.
‫Lassen Sie mich Ihnen jetzt nur zeigen, wie es funktioniert,
‫wenn wir es hier beispielsweise auf 16 setzen.
‫Und ich muss die E-Mail hier ändern.
‫Und so sollte das jetzt viel Zeit in Anspruch nehmen und ich bin mir
‫nicht sicher, ob ich überhaupt warten kann.
‫Oh, eigentlich hat es viereinhalb Sekunden gedauert.
‫Aber das ist glaube ich immer noch ein bisschen zu viel, okay?
‫Also, setzen wir es
‫zurück auf
‫12 und das sollte besser sein, okay?
‫Und jetzt löschen wir einfach noch
‫einmal diese Benutzer hier, die wir gerade erstellt haben.
‫Und eigentlich muss ich diesen
‫ersten loswerden, weil dieser noch das Passwort im Klartext hat.
‫Dieser Benutzer wird also
‫nicht funktionieren, wenn wir anfangen,
‫Benutzer anhand ihres Passworts anzumelden.
‫Okay?
‫Also lass uns das loswerden.
‫Okay?
‫Und was ich Ihnen hier auch zeigen
‫wollte, ist, dass wir für diese beiden Benutzer
‫genau dasselbe Passwort eingeben, das wir erstellt haben, oder?
‫Aber Sie sehen, dass
‫das verschlüsselte Passwort tatsächlich ganz anders ist, oder?
‫Und das ist die Macht, das Passwort zu salzen,
‫bevor es gehasht wird.
‫Gut?
‫So haben wir auch hier wieder ein sehr sicheres
‫und gutes Passwortmanagement implementiert.