‫Istruttore: E ora creiamo finalmente l'ultima parte della
‫funzionalità di reimpostazione della
‫password, dove impostiamo effettivamente la nuova password per l'utente.
‫E quindi, proprio come prima, iniziamo definendo
‫i passaggi che seguiremo per questo flusso di resetPassword.
‫Quindi, prima di tutto, ottieni l'utente in base al token.
‫Quindi, come secondo passaggio, imposteremo la nuova password ma
‫solo se il token non è scaduto e
‫c'è un utente.
‫Quindi, in tal caso, imposta la nuova password.
‫Successivamente, è necessario aggiornare la proprietà
‫changePasswordAt per l'utente corrente e infine, come
‫al solito
‫in questa funzionalità, eseguire l'accesso
‫dell'utente.
‫Fondamentalmente, invia il token Web JSON al client.
‫Ok, c'è tanto lavoro da fare, quindi cominciamo.
‫E quindi, ricorda dall'ultimo video, che il token di
‫ripristino che viene effettivamente inviato nell'URL è
‫questo token non crittografato qui.
‫Quindi, in realtà questo.
‫Ma quello che abbiamo nel
‫database è quello crittografato.
‫Quindi ne abbiamo parlato prima, e quindi quello che
‫dobbiamo fare ora è fondamentalmente crittografare
‫di nuovo il token
‫originale, quindi possiamo confrontarlo con quello che è
‫archiviato, quindi quello crittografato nel database.
‫Quindi, in realtà abbiamo fatto qualcosa di
‫simile prima con la password, ma con la password
‫non abbiamo potuto confrontarla facilmente come possiamo con questa, ancora
‫una volta perché per
‫la password abbiamo usato l'algoritmo bcrypt piuttosto complesso, che in
‫questo caso, non l'abbiamo fatto.
‫Quindi, qui è molto semplice.
‫Tutto ciò che dobbiamo fare di nuovo
‫è crittografare il token e confrontarlo con quello crittografato nel database.
‫Quindi, diciamo hashToken, e quindi ora avremo bisogno
‫del pacchetto crittografico anche qui.
‫Const crypto e poi require('crypto').
‫Ora giusto.
‫Poi torniamo indietro, e così usiamo
‫le criptovalute. createHash.
‫Ricorda, quindi di nuovo il nome dell'algoritmo,
‫sha256, quindi . aggiornamento, fondamentalmente per il luogo, per la
‫stringa che vogliamo hash.
‫E così, quello è, ricorda in req. parametri.
‫Quindi usiamo questo per molto tempo. gettone.
‫E così di nuovo, è un
‫parametro, perché lo abbiamo specificato qui nell'URL, quindi così.
‫Quindi, ora è un parametro chiamato token.
‫E quindi, ovviamente, qui è req. parametri. gettone.
‫E poi, infine, dobbiamo anche dire digest
‫e convertirlo in esadecimale.
‫Ora questo è fondamentalmente lo stesso
‫di prima, in cui abbiamo crittografato quello originale, e
‫quindi abbiamo potuto rifattorizzarlo nella sua funzione, ma manteniamo
‫le cose semplici qui.
‫Quindi, ora otteniamo effettivamente l'utente in base a questo token.
‫Perché questa è in realtà l'unica
‫cosa che sappiamo dell'utente in questo momento.
‫Non abbiamo email, non abbiamo nulla, quindi questo token
‫è l'unica cosa che può identificare l'utente.
‫E quindi ora possiamo, in pratica, interrogare il
‫database per questo token.
‫E troverà quindi l'utente che ha questo token.
‫Quindi, aspetta, come già sappiamo, e poi Utente. trova uno.
‫Quindi, quella proprietà si
‫chiama passwordResetToken e stiamo cercando l'hashedToken.
‫E ora, ovviamente, dobbiamo dichiararlo asincrono e prepararlo
‫in catchAsync.
‫Dagli un salvataggio, che dovrebbe risolvere questo bug,
‫e in effetti lo fa.
‫Quindi, questo troverà l'utente che ha il
‫token che invierà tramite URL.
‫Ma, in questo momento, non
‫stiamo prendendo in considerazione la data di scadenza del token.
‫E quindi come potremmo farlo?
‫Bene, in pratica, ciò che vogliamo è
‫verificare se la proprietà passwordResetExpires è maggiore
‫di quella attuale.
‫Perché se la data di scadenza è maggiore di
‫quella attuale, significa che è nel futuro, il che a sua volta
‫significa che non è ancora scaduta.
‫E quindi, questo è un
‫modo molto semplice in cui possiamo effettivamente farlo correttamente con questa query.
‫Quindi, passwordResetExpires, che è dove è
‫memorizzata quella data, e ora tutto
‫ciò che serve
‫per verificare se è effettivamente maggiore di adesso.
‫E quindi sappiamo già come farlo con MongoDB, giusto?
‫Quindi, nuovo oggetto e quindi l'operatore maggiore e quindi ciò con cui
‫vogliamo confrontarlo è Data. ora, e questo sarà
‫effettivamente un timestamp di adesso, ma dietro
‫le quinte, MongoDB convertirà tutto allo stesso modo,
‫e quindi sarà in grado di
‫confrontarli accuratamente.
‫E così con questo possiamo, allo stesso
‫tempo, trovare l'utente per il token e anche verificare se il
‫token non è ancora scaduto.
‫Quindi, fantastico.
‫Quindi, in seguito vogliamo, ovviamente, inviare un errore
‫se non ci sono utenti o, in pratica, se il token è scaduto.
‫Ma in questo caso
‫è lo stesso, perché se il token è scaduto,
‫beh, semplicemente non restituirà alcun utente.
‫E quindi tutto ciò che dobbiamo fare è dire,
‫se nessun utente, beh, allora, come sempre, torna dopo, non è corretto.
‫Quindi nuovo AppError e diciamo che
‫il token non è valido o è scaduto.
‫E poi 400, quindi brutta richiesta.
‫E quindi, se non ci sono errori
‫e se next non viene
‫chiamato, allora impostiamo effettivamente la password.
‫Quindi, abbiamo già ottenuto l'utente e ora è molto
‫semplice: utente. la password è uguale a req. corpo. parola d'ordine.
‫E questo perché, ovviamente, invieremo la
‫password e anche la passwordConfirm tramite il corpo.
‫Quindi duplichiamo
‫anche quello e passwordConfirm.
‫E poi, in pratica, eliminiamo il token di ripristino
‫e quello scaduto.
‫Quindi passwordResetToken, proprio come abbiamo fatto prima, lo impostiamo su
‫undefined e ora user. la password scade è uguale
‫a undefined.
‫Va bene.
‫E ancora, ovviamente, ora dobbiamo salvarlo,
‫perché questo modifica solo il documento, non
‫si aggiorna davvero.
‫Quindi non lo salva davvero.
‫Quindi, attendi utente. Salva.
‫E in questo caso, in realtà
‫non dobbiamo disattivare i validatori, perché in effetti vogliamo convalidare.
‫Ad esempio, vogliamo che il validatore
‫confermi se la password è uguale a passwordConfirm.
‫E così quel validatore fa automaticamente tutto
‫ciò che funziona per noi.
‫Quindi il terzo passaggio, quello che faremo in
‫realtà alla fine, e quindi quello che faremo
‫dopo è sostanzialmente bloccare l'utente.
‫Quindi, in altre parole, invia il token Web JSON.
‫E prendiamo quel codice da qui, quindi questo.
‫E ancora, lo stiamo già
‫facendo qui in tre posti diversi.
‫Quindi qui nel login, anche nella registrazione, e ora
‫per la terza volta, quaggiù.
‫E così, in futuro, lo riformeremo nella
‫sua funzione.
‫Ma per ora siamo a posto così.
‫E quindi, ora andiamo avanti e proviamo questo.
‫Quindi questo token di ripristino
‫che avevamo prima è già scaduto, quindi
‫dobbiamo chiederne uno nuovo, in pratica.
‫Quindi veniamo da Postman e seguiamo il nostro percorso per dimenticare la password.
‫Riduciamo il disordine qui ed
‫eliminiamo tutte queste schede aperte di cui non abbiamo
‫più bisogno.
‫In realtà qui avremo bisogno di
‫questo test per questa reimpostazione
‫della password, perché ricorda, questo in realtà restituisce un
‫token Web JSON e quindi vogliamo salvarlo nella variabile d'ambiente,
‫proprio come abbiamo
‫fatto con tutti gli altri.
‫Quindi lo sto facendo ora, solo per non dimenticarlo.
‫Va bene, comunque, iniziamo con, in pratica,
‫dimenticando la password.
‫Quindi inviare quella richiesta, che di nuovo richiede
‫del tempo a causa dell'invio
‫dell'e-mail, ma ci siamo, e ora andiamo alla nostra e-mail, e
‫quindi è arrivata solo pochi secondi fa.
‫Quindi, è questo, ovviamente, questo token.
‫Quindi prendiamolo, copiamolo e ora torniamo a Postman, lo usiamo
‫in Reimposta password, come URL.
‫Ok, ha senso?
‫Quindi, di nuovo, stiamo inviando quel token direttamente nell'URL.
‫Quindi qui, specifichiamo il corpo,
‫perché ora dobbiamo specificare effettivamente la nostra nuova password.
‫Quindi password e diciamo newpass.
‫Poi...
‫E qui chiamiamolo in un
‫altro modo, perché per ora voglio davvero vedere un errore.
‫E, naturalmente, si chiama passwordConfirm.
‫Quindi vediamo cosa succede quando proviamo a farlo.
‫Aspettiamo e otteniamo che la password sia più
‫corta della lunghezza minima consentita.
‫Ok, allora cambiamolo, 123, e qui diciamo 1234.
‫Quindi voglio che siano diversi.
‫Ma vedi che la convalida qui ha funzionato bene,
‫anche durante l'aggiornamento della password con save.
‫Quindi, e ora otteniamo le password non sono le stesse!
‫Quindi di nuovo, questo è un errore di convalida.
‫E ricorda, in realtà, che questo è l'intero
‫motivo per cui dobbiamo usare il salvataggio e non l'aggiornamento.
‫Quindi prima, per aggiornare
‫i tour, usavamo findOneAndUpdate, ma ora, per tutto ciò
‫che riguarda le password e l'utente, usiamo sempre
‫save, perché vogliamo sempre eseguire tutti i
‫validatori, e soprattutto le funzioni di
‫salvataggio del middleware.
‫Quindi, ad esempio, quelli in cui le password sono crittografate.
‫Quindi finiamola adesso.
‫Oh, in realtà non l'ho corretto, scusa per quello.
‫E ora dovrebbe funzionare davvero.
‫E infatti, otteniamo successo e otteniamo un nuovo token.
‫Ottimo, vediamo se questo token è effettivamente valido.
‫Quindi, se possiamo, ottieni tutti i tour usando questo nuovissimo token.
‫E qui andiamo.
‫Quindi, il nostro nuovo token funziona davvero, e ora per questo
‫utente, quindi per hello@jonas, queste due proprietà
‫dovrebbero effettivamente essere sparite.
‫Quindi la password scade e il token dovrebbe essere sparito,
‫poiché, beh, poiché è quello che abbiamo fatto nel nostro codice.
‫E quindi, sì, non sono più qui.
‫Ora tutto ciò che dobbiamo fare in realtà è questo passaggio
‫mancante qui, ovvero aggiornare la proprietà passwordAt per
‫questo utente corrente.
‫Ma non dovrebbe
‫essere troppo difficile, quindi torniamo rapidamente a
‫userModel, che è dove lo faremo usando il middleware.
‫E mettiamo insieme tutto il
‫middleware qui in alto.
‫Quindi, userSchema. pre e ancora
‫punto save, e poi una funzione con next.
‫Di nuovo, questa funzione verrà
‫eseguita subito prima che un nuovo documento venga effettivamente salvato.
‫E quindi, è
‫il posto perfetto per specificare effettivamente questa proprietà.
‫E avrei potuto, ovviamente, farlo in un controller
‫proprio accanto a questo codice, per esempio.
‫Ma voglio davvero che questo accada, in modo automatico.
‫Quindi, un po' dietro le quinte.
‫Perché in seguito, avremo un altro posto
‫in cui aggiorneremo la password e quindi ci assicureremo di
‫includere lo stesso codice lì.
‫E così, di nuovo, accade,
‫un po' dietro
‫le quinte, senza che noi dobbiamo preoccuparcene affatto.
‫Ora, quando esattamente vogliamo
‫impostare la proprietà passwordChangedAt su adesso?
‫Bene, lo vogliamo solo quando abbiamo effettivamente modificato la
‫proprietà della password.
‫E non sono sicuro che abbiamo usato questo
‫trucco prima, ma comunque, usiamolo ora.
‫Quindi se non abbiamo modificato, quindi se non questo. isModified, quindi proprio come
‫questo, e
‫poi il nome della proprietà, quindi password.
‫Quindi, in tal caso, torna subito ed
‫esegui il prossimo middleware.
‫Ok, non così, ma così.
‫Quindi, ancora una volta, se non
‫abbiamo
‫modificato la proprietà password, ovviamente non manipolare passwordChangedAt.
‫Ma per quanto riguarda la creazione di un nuovo documento?
‫Bene, quando creiamo un nuovo
‫documento, abbiamo effettivamente modificato
‫la password e quindi abbiamo impostato la proprietà passwordChangedAt, giusto?
‫Bene, nell'attuale implementazione lo faremmo davvero.
‫Ma c'è qualcos'altro che possiamo usare qui.
‫Quindi, in sostanza, vogliamo uscire subito da
‫questa funzione middleware, se la password non è stata modificata
‫o se il documento è nuovo, e quindi possiamo usare
‫la proprietà isNew.
‫E ancora, questa è una di queste cose molto belle che
‫si imparano leggendo la documentazione.
‫E quindi, non posso sottolineare abbastanza quanto sia importante leggere davvero
‫la documentazione quando hai bisogno di qualcosa che non puoi
‫trovare da nessuna parte.
‫Perché ci sono davvero così
‫tante cose lì dentro che è completamente impossibile insegnare in un corso.
‫Ad ogni modo, se il codice supera questa
‫verifica qui, beh, allora diciamo
‫semplicemente questo. passwordChangedAt = Data. Ora.
‫E poi, chiamiamo il prossimo.
‫Ora, in teoria, dovrebbe funzionare bene, ma in
‫realtà, in pratica,
‫a volte si verifica un piccolo problema.
‫E quel problema è che a volte il salvataggio nel
‫database è un po' più lento rispetto all'emissione del token Web
‫JSON, in modo che il timestamp della password modificato
‫a volte venga impostato un
‫po' dopo la creazione del token Web JSON.
‫E così ciò farà in modo
‫che l'utente non possa accedere utilizzando il nuovo token.
‫Perché, ricorda, l'intera ragione per cui questo timestamp
‫qui esiste effettivamente, è che possiamo
‫confrontarlo con il timestamp sul token Web JSON, giusto?
‫Quindi, giusto per ricordare, è, beh,
‫proprio qui, dove controlliamo se l'utente ha cambiato la password
‫dopo che il token è stato emesso.
‫E così, quaggiù, dove abbiamo quindi creato questo nuovo
‫token in reimposta password.
‫Quindi proprio qui, ricorda, creiamo questo nuovo token,
‫e così di nuovo, a volte capita che questo
‫token venga creato un po' prima che il timestamp della
‫password modificata sia stato effettivamente creato.
‫E quindi, dobbiamo solo aggiustarlo sottraendo un secondo.
‫Quindi, in pratica, mille millisecondi.
‫E quindi metterà la passwordChangedAt un secondo nel passato,
‫ok, il che ovviamente non sarà
‫accurato al 100%, ma non è affatto un problema,
‫perché un secondo qui non fa alcuna differenza.
‫È un piccolo trucco, ma ancora una volta, non è un problema.
‫Quindi, inserire questa passwordChanged un secondo in passato, assicurerà che
‫il token venga sempre creato dopo che
‫la password è stata modificata.
‫Quindi, ora funziona,
‫ma come sempre, proviamolo rapidamente.
‫Ok, allora torniamo al postino.
‫Facciamo un nuovo Reset Password, o in realtà,
‫non è proprio quello che
‫volevo, ma è un'ottima cosa vedere che
‫il codice funziona davvero.
‫Quindi, il token non è valido o è scaduto, e
‫questo perché, beh, sono trascorsi 10
‫minuti da quando ho effettivamente creato quel token.
‫E penso che non l'avessimo ancora
‫testato, quindi è fantastico che ora l'abbia fatto accidentalmente.
‫Quindi di nuovo, questo viene, nel caso ti stia chiedendo cosa diavolo
‫è successo, quindi
‫questo è ovviamente questo messaggio di errore qui.
‫E quindi significa che non ha trovato nessun utente
‫che ha questo token o che ha un token che è più
‫di 10 minuti nel passato.
‫E quindi, in effetti, quello che volevo fare era dimenticare la password.
‫Quindi, aspettiamo.
‫Quindi 8. 6 secondi,
‫ma potrebbe essere dovuto alla mia connessione Internet.
‫Quindi, se lo esegui su
‫un server, probabilmente sarà molto più veloce.
‫Quindi prendiamolo qui, di nuovo a Postman, e ora
‫reimpostiamo la password, di nuovo con questa password, non importa se
‫è la stessa di quella vecchia.
‫E così ora abbiamo il nostro successo qui.
‫E ora torniamo a Compass.
‫Ricarichiamo, e infatti, otteniamo la passwordChangedAt.
‫E quindi è proprio ora.
‫E quindi, se ora provassimo a utilizzare effettivamente questo token, ad esempio,
‫per accedere a questo percorso protetto, allora dovrebbe
‫funzionare a causa di quel piccolo
‫tag di un secondo che abbiamo fatto.
‫Così è stato e così, in questo momento, abbiamo terminato la
‫nostra funzionalità di reimpostazione della password.
‫Quindi era un bel po' di codice, ma ovviamente
‫ne valeva la pena.
‫Quindi, dovresti sempre offrire questa
‫funzionalità nella tua applicazione web, perché altrimenti,
‫un utente che dimentica la sua password è completamente fregato, non
‫può più utilizzare la tua applicazione,
‫e quindi questa è ovviamente una pratica terribile.
‫In ogni caso, questo tipo
‫di completamento termina, già, la parte di autenticazione e autorizzazione di questa sezione.
‫Quindi, di nuovo, è abbastanza
‫completo e mi sono divertito molto a implementarlo.
‫Quindi, questa parte per me è dove le applicazioni
‫web iniziano davvero a prendere vita.
‫So che a questo punto non è davvero visibile,
‫con tutti questi, solo token e copia di token e
‫incollali da qualche altra parte.
‫Non è la solita idea che abbiamo di accedere, lo
‫so, ma ovviamente di nuovo, un po' più
‫tardi, quando finalmente inizieremo a costruire il sito Web
‫dinamico, continueremo
‫ovviamente a utilizzare questa autenticazione che abbiamo
‫appena creato e poi diventerà anche visivo su quel sito web dinamico.
‫Successivamente, implementeremo la funzionalità per aggiornare
‫l'utente e anche per
‫eliminarlo, quindi parleremo anche della sicurezza.
‫Questo è ciò che ci aspetta per il resto
‫della sezione, quindi assicurati di non perderlo.