‫Instruktur: Dan sekarang mari kita akhirnya membuat bagian terakhir
‫dari Fungsi Pengaturan Ulang Kata Sandi,
‫di mana kita sebenarnya mengatur kata sandi baru untuk pengguna.
‫Jadi, seperti sebelumnya, mari kita mulai dengan mendefinisikan
‫langkah-langkah yang akan kita ambil untuk alur resetPassword ini.
‫Jadi, pertama-tama, dapatkan pengguna berdasarkan token.
‫Kemudian sebagai langkah kedua, kami akan mengatur kata sandi
‫baru tetapi hanya jika token belum kedaluwarsa,
‫dan ada pengguna.
‫Jadi dalam hal ini, atur kata sandi baru.
‫Kemudian setelah itu, kita perlu memperbarui
‫properti ChangePasswordAt untuk pengguna saat ini, dan
‫terakhir, seperti
‫biasa dalam fungsi ini, adalah memasukkan
‫pengguna.
‫Pada dasarnya, kirim Token Web JSON ke klien.
‫Oke, begitu banyak pekerjaan yang harus dilakukan, jadi mari kita mulai.
‫Jadi, ingat dari video terakhir, bahwa token reset
‫yang sebenarnya dikirim di URL adalah token
‫yang tidak dienkripsi di sini.
‫Jadi, sebenarnya yang ini.
‫Tapi yang kita punya di
‫database adalah yang terenkripsi.
‫Jadi kita sudah membicarakannya sebelumnya, dan sekarang yang
‫perlu kita lakukan, pada dasarnya adalah
‫mengenkripsi token asli
‫lagi, jadi kita bisa membandingkannya dengan yang
‫disimpan, jadi yang terenkripsi di database.
‫Jadi, kami sebenarnya melakukan sesuatu yang serupa
‫sebelumnya dengan kata sandi, tetapi dengan kata sandi, kami
‫tidak dapat membandingkannya semudah yang kami bisa dengan yang ini,
‫sekali lagi karena untuk
‫kata sandi kami menggunakan algoritma bcrypt yang cukup rumit, yang
‫dalam hal ini, kami tidak.
‫Jadi, di sini sangat mudah.
‫Yang perlu kita lakukan lagi, adalah
‫mengenkripsi token dan membandingkannya dengan yang terenkripsi di database.
‫Jadi, katakanlah hashedToken, jadi kita sekarang akan benar-benar membutuhkan
‫paket crypto di sini juga.
‫Const crypto dan kemudian require('crypto').
‫Sekarang benar.
‫Kalau begitu mari kita kembali, jadi, kita
‫menggunakan kripto. buatHash.
‫Ingat, lalu nama algoritmanya lagi, sha256,
‫lalu . perbarui, pada dasarnya untuk tempat, untuk string
‫yang ingin kita hash.
‫Jadi, yang itu, ingat di req. param
‫Jadi kami kemudian menggunakan yang ini untuk waktu yang lama. token.
‫Dan sekali lagi, ini adalah parameter,
‫karena kami menentukannya di sini di URL, jadi seperti ini.
‫Jadi, sekarang parameter yang disebut token.
‫Jadi, tentu saja, ini req. param token.
‫Dan kemudian, akhirnya, kita juga perlu mengatakan mencerna
‫dan mengubahnya menjadi heksadesimal.
‫Sekarang ini pada dasarnya sama seperti yang
‫kita miliki sebelumnya, di mana kita mengenkripsi yang asli, dan
‫jadi kita bisa refactor ini menjadi fungsinya sendiri, tapi mari
‫kita buat sederhana di sini.
‫Jadi, sekarang mari kita benar-benar mendapatkan pengguna berdasarkan token ini.
‫Karena hanya itu yang
‫kami ketahui tentang pengguna saat ini.
‫Kami tidak memiliki email, kami tidak memiliki apa-apa, jadi token
‫ini adalah satu-satunya yang dapat mengidentifikasi pengguna.
‫Jadi sekarang kita bisa, pada dasarnya, menanyakan
‫database untuk token ini.
‫Dan kemudian akan menemukan pengguna yang memiliki token ini.
‫Jadi, tunggu, seperti yang sudah kita ketahui, dan kemudian Pengguna. temukanSatu.
‫Jadi, properti itu disebut
‫passwordResetToken dan kami mencari hashedToken.
‫Dan sekarang tentu saja, kita perlu mendeklarasikannya sebagai async dan
‫menyiapkannya ke catchAsync.
‫Berikan simpanan, yang seharusnya memperbaiki bug ini,
‫dan memang benar.
‫Jadi, ini akan menemukan pengguna yang memiliki token
‫yang akan dikirim melalui URL.
‫Namun, saat ini,
‫kami tidak mempertimbangkan tanggal kedaluwarsa token.
‫Dan jadi bagaimana kita bisa melakukan itu?
‫Yah, pada dasarnya, yang kita inginkan
‫adalah memeriksa apakah properti passwordResetExpires lebih
‫besar dari sekarang.
‫Karena jika expired date lebih besar
‫dari sekarang, berarti masih di masa depan yang
‫artinya belum expired.
‫Jadi, itulah cara yang sangat
‫mudah di mana kita benar-benar dapat melakukannya dengan benar dengan kueri ini.
‫Jadi, passwordResetExpires, di mana tanggal
‫itu disimpan, dan sekarang kita hanya
‫perlu memeriksa
‫apakah tanggal itu lebih besar dari sekarang.
‫Jadi kita sudah tahu bagaimana melakukannya dengan MongoDB, bukan?
‫Jadi, objek baru dan kemudian operator yang lebih besar dan kemudian yang ingin
‫kita bandingkan adalah Date. sekarang, dan ini sebenarnya
‫akan menjadi stempel waktu sekarang, tetapi di
‫balik layar, MongoDB kemudian akan mengubah semuanya menjadi
‫sama, dan karena itu dapat membandingkannya
‫secara akurat.
‫Jadi dengan ini kita dapat, pada
‫saat yang sama, menemukan pengguna untuk token dan juga memeriksa
‫apakah token tersebut belum kedaluwarsa.
‫Sangat bagus.
‫Jadi, selanjutnya kami ingin, tentu saja, mengirim
‫kesalahan jika tidak ada pengguna, atau pada dasarnya, jika token telah kedaluwarsa.
‫Tapi itu, dalam hal
‫ini, sama, karena jika token telah kedaluwarsa, maka itu
‫tidak akan mengembalikan pengguna mana pun.
‫Jadi yang perlu kita lakukan adalah mengatakan, jika
‫tidak ada pengguna, maka, seperti biasa, kembali berikutnya, itu bukan mext.
‫Jadi AppError baru, dan
‫katakanlah Token tidak valid atau telah kedaluwarsa.
‫Dan kemudian 400, permintaan yang sangat buruk.
‫Jadi, jika tidak ada kesalahan, dan
‫jika berikutnya tidak dipanggil,
‫maka mari kita atur kata sandinya.
‫Jadi, kami sudah mendapatkan pengguna dan sekarang sangat
‫sederhana: pengguna. kata sandi sama dengan req. tubuh. kata sandi.
‫Dan itu karena kami tentu saja akan
‫mengirimkan kata sandi dan juga kata sandiKonfirmasi melalui badan.
‫Jadi mari kita gandakan
‫itu dan konfirmasi kata sandi juga.
‫Dan juga, mari kita pada dasarnya menghapus token reset
‫dan yang kedaluwarsa.
‫Jadi passwordResetToken, jadi seperti yang kita lakukan sebelumnya, kita set ke
‫undefined, dan sekarang user. kata sandi kedaluwarsa sama dengan
‫tidak terdefinisi.
‫Baiklah.
‫Dan lagi, tentu saja, sekarang kita
‫perlu menyimpannya, karena ini hanya mengubah dokumen,
‫tidak benar-benar memperbarui.
‫Jadi itu tidak benar-benar menyelamatkannya.
‫Jadi, tunggu pengguna. menyimpan.
‫Dan dalam hal ini sebenarnya kita
‫tidak perlu mematikan validator, karena memang kita ingin melakukan validasi.
‫Misalnya, kami ingin validator mengonfirmasi
‫apakah kata sandi sama dengan kata sandiKonfirmasi.
‫Dan validator itu secara otomatis melakukan
‫semua itu untuk kita.
‫Kemudian langkah ketiga, apa yang akan kita
‫lakukan pada akhirnya, dan apa yang akan kita
‫lakukan selanjutnya adalah mengunci pengguna.
‫Jadi dengan kata lain, kirim JSON Web Token.
‫Dan mari kita ambil kode itu dari sini, jadi yang ini.
‫Dan sekali lagi, kami sudah
‫melakukan ini di tiga tempat berbeda.
‫Jadi di sini di login, juga di signup, dan sekarang
‫untuk ketiga kalinya, di sini.
‫Jadi, suatu saat nanti, kami akan refactor itu menjadi
‫fungsinya sendiri.
‫Tapi untuk saat ini, kami baik-baik saja seperti ini.
‫Jadi, sekarang mari kita lanjutkan dan uji ini.
‫Jadi token reset yang
‫kita miliki sebelumnya sudah kedaluwarsa, jadi pada
‫dasarnya kita perlu meminta yang baru.
‫Jadi mari datang ke Postman dan tekan rute lupa kata sandi kami.
‫Mari kita kurangi kekacauan di
‫sini dan singkirkan semua tab terbuka yang tidak lagi
‫kita perlukan.
‫Sebenarnya di sini kita akan membutuhkan
‫tes ini untuk Reset Password
‫ini, karena ingat, yang ini benar-benar mendapatkan kembali Token
‫Web JSON, dan jadi kami ingin menyimpannya ke dalam variabel
‫lingkungan, seperti yang
‫kami lakukan dengan yang lainnya.
‫Jadi saya melakukan itu sekarang, hanya agar saya tidak melupakannya.
‫Baiklah, bagaimanapun, mari kita mulai dengan, pada dasarnya,
‫melupakan kata sandi.
‫Jadi mengirimkan permintaan itu, yang sekali lagi, membutuhkan
‫waktu karena mengirim email, tapi
‫ini dia, dan sekarang mari kita pergi ke email kita, dan itu
‫baru saja tiba beberapa detik yang lalu.
‫Jadi, ini, tentu saja, token ini.
‫Jadi mari kita ambil, salin dan sekarang kembali ke Postman, kita
‫menggunakannya di Reset Password, sebagai URL.
‫Oke, masuk akal?
‫Jadi sekali lagi, kami mengirimkan token itu tepat di URL.
‫Kemudian di sini, mari tentukan
‫isi, karena sekarang, kita perlu benar-benar menentukan kata sandi baru kita.
‫Jadi kata sandi dan katakanlah newpass.
‫Lalu...
‫Dan di sini sebut saja
‫sesuatu yang lain, karena untuk saat ini, saya sebenarnya ingin melihat kesalahan.
‫Dan tentu saja, ini disebut passwordConfirm.
‫Jadi mari kita lihat apa yang terjadi ketika kita mencoba melakukan ini.
‫Mari kita tunggu, dan kita mendapatkan kata sandi lebih
‫pendek dari panjang minimum yang diizinkan.
‫Oke, jadi mari kita ubah itu, 123, dan di sini katakanlah 1234.
‫Jadi saya ingin mereka berbeda.
‫Tetapi Anda melihat bahwa validasi di sini berfungsi dengan
‫baik, bahkan ketika memperbarui kata sandi dengan simpan.
‫Jadi, dan sekarang kita mendapatkan Password yang tidak sama!
‫Jadi sekali lagi, itu adalah kesalahan validasi.
‫Dan ingat, sebenarnya, inilah alasan mengapa
‫kita perlu menggunakan save and not update.
‫Jadi sebelumnya, untuk memperbarui
‫tur, kami biasanya menggunakan findOneAndUpdate, tetapi sekarang, untuk semua
‫yang terkait dengan kata sandi dan pengguna, kami
‫selalu menggunakan save, karena kami selalu ingin
‫menjalankan semua validator, dan yang terpenting,
‫fungsi save middleware.
‫Jadi, misalnya, yang kata sandinya dienkripsi.
‫Jadi mari kita akhiri sekarang.
‫Oh, saya tidak benar-benar memperbaikinya, maaf untuk itu.
‫Dan sekarang itu harus benar-benar berfungsi.
‫Dan memang, kami mendapatkan kesuksesan, dan kami mendapatkan token baru.
‫Hebat, mari kita lihat apakah token ini benar-benar valid.
‫Jadi jika kami bisa, dapatkan semua tur menggunakan token baru ini.
‫Dan ini dia.
‫Jadi, token baru kami benar-benar berfungsi, dan sekarang untuk pengguna
‫ini, jadi untuk hello@jonas, kedua properti
‫ini harus benar-benar hilang.
‫Jadi kata sandinya kedaluwarsa dan tokennya harus hilang,
‫karena, yah, karena itulah yang kami lakukan dalam kode kami.
‫Jadi, ya, mereka tidak lagi di sini.
‫Sekarang yang perlu kita lakukan sebenarnya, adalah langkah yang hilang ini
‫di sini, yaitu memperbarui properti passwordAt untuk
‫pengguna saat ini.
‫Tapi itu seharusnya
‫tidak terlalu sulit, jadi mari kita cepat kembali
‫ke userModel, di mana kita akan melakukannya menggunakan middleware.
‫Dan mari kita menempatkan semua middleware
‫bersama-sama di sini di atas.
‫Jadi, skema pengguna. pra dan
‫lagi titik simpan, dan kemudian fungsi dengan berikutnya.
‫Sekali lagi, fungsi ini di
‫sini akan berjalan tepat sebelum dokumen baru benar-benar disimpan.
‫Jadi, ini adalah
‫tempat yang tepat untuk benar-benar menentukan properti ini.
‫Dan saya, tentu saja, dapat melakukannya di pengontrol
‫tepat di sebelah kode ini, misalnya.
‫Tapi saya benar-benar ingin ini terjadi, secara otomatis.
‫Jadi, semacam di belakang layar.
‫Karena nanti, kami akan memiliki tempat lain di
‫mana kami memperbarui kata sandi dan kemudian kami akan memastikan bahwa kami
‫memasukkan kode yang sama di sana.
‫Dan seperti ini, sekali lagi,
‫itu terjadi, semacam,
‫di belakang layar, tanpa kita harus mengkhawatirkannya sama sekali.
‫Sekarang, kapan tepatnya kita
‫ingin menyetel properti passwordChangedAt menjadi sekarang?
‫Kami hanya menginginkannya ketika kami benar-benar mengubah
‫properti kata sandi.
‫Dan saya tidak yakin apakah kita pernah menggunakan trik
‫ini sebelumnya, tapi bagaimanapun, mari kita gunakan sekarang.
‫Jadi kalau belum kita modifikasi, ya kalau tidak ini. isModified, jadi seperti ini,
‫dan
‫kemudian nama properti, jadi kata sandi.
‫Jadi dalam hal ini, segera kembali dan
‫jalankan middleware berikutnya.
‫Oke, tidak seperti ini, tapi seperti ini.
‫Jadi sekali lagi, jika kita tidak
‫mengubah
‫properti password, tentu saja, jangan memanipulasi passwordChangedAt.
‫Tapi bagaimana dengan membuat dokumen baru?
‫Nah, ketika kita membuat dokumen baru,
‫maka kita benar-benar memodifikasi
‫kata sandi, dan kemudian kita akan mengatur properti kata sandiChangedAt, kan?
‫Nah, dalam implementasi saat ini sebenarnya kita akan melakukannya.
‫Tapi ada hal lain yang bisa kita gunakan di sini.
‫Jadi, pada dasarnya, kami ingin segera keluar
‫dari fungsi middleware ini, jika kata sandinya belum diubah
‫atau jika dokumennya baru, sehingga kami dapat menggunakan
‫properti isNew.
‫Dan sekali lagi, ini adalah salah satu hal yang sangat bagus
‫yang dipelajari dengan membaca dokumentasi Anda.
‫Jadi, saya tidak bisa cukup menekankan betapa pentingnya untuk benar-benar membaca
‫dokumentasi ketika Anda membutuhkan sesuatu yang tidak dapat Anda
‫temukan di mana pun.
‫Karena, sebenarnya ada begitu banyak hal
‫di sana yang sama sekali tidak mungkin untuk diajarkan dalam satu mata kuliah.
‫Bagaimanapun, jika kode melewati verifikasi ini di
‫sini, maka katakan saja,
‫ini. passwordChangedAt = Tanggal. sekarang.
‫Dan kemudian, kami menelepon berikutnya.
‫Sekarang, secara teori, ini seharusnya berfungsi dengan
‫baik, tetapi sebenarnya,
‫dalam praktiknya, terkadang masalah kecil terjadi.
‫Dan masalahnya terkadang menyimpan ke database sedikit
‫lebih lambat daripada mengeluarkan JSON Web Token, sehingga
‫timestamp kata sandi yang diubah terkadang
‫diatur sedikit setelah
‫JSON Web Token dibuat.
‫Dan itu kemudian akan membuat pengguna
‫tidak akan bisa login menggunakan token baru.
‫Karena, ingat, alasan mengapa stempel waktu ini benar-benar
‫ada, adalah agar kita dapat membandingkannya
‫dengan stempel waktu di JSON Web Token, bukan?
‫Jadi, untuk diingat, ya, jadi
‫di sini, di mana kami memeriksa apakah pengguna telah
‫mengubah kata sandi setelah token dikeluarkan.
‫Jadi, di sini, di mana kami kemudian membuat token
‫baru ini di reset password.
‫Jadi di sini, ingat, kita membuat
‫token baru ini, dan sekali lagi, terkadang token
‫ini dibuat sedikit sebelum cap waktu kata sandi
‫yang diubah benar-benar dibuat.
‫Jadi, kita hanya perlu memperbaikinya dengan mengurangi satu detik.
‫Jadi, pada dasarnya, seribu milidetik.
‫Dan kemudian akan menempatkan passwordChangedAt satu detik di masa lalu,
‫oke, yang tentu saja, tidak 100%
‫akurat, tapi itu tidak masalah sama sekali, karena satu
‫detik di sini tidak ada bedanya sama sekali.
‫Ini adalah peretasan kecil, tetapi sekali lagi, itu tidak masalah.
‫Jadi menempatkan passwordChanged ini satu detik di masa lalu,
‫maka akan memastikan bahwa token selalu
‫dibuat setelah password diubah.
‫Jadi, ini berfungsi sekarang, tetapi seperti
‫biasa, mari kita juga mengujinya dengan cepat.
‫Oke, jadi kembali ke tukang pos.
‫Mari kita lakukan Reset Kata Sandi baru, atau sebenarnya,
‫bukan itu yang saya inginkan sama
‫sekali, tetapi merupakan hal yang hebat untuk melihat
‫bahwa kode tersebut benar-benar berfungsi.
‫Jadi, Token tidak valid atau telah kedaluwarsa, dan itu
‫karena, yah, 10 menit telah
‫berlalu sejak saya benar-benar membuat token itu.
‫Dan saya pikir kami belum menguji
‫ini, dan sangat bagus bahwa sekarang secara tidak sengaja, benar-benar melakukannya.
‫Jadi sekali lagi, ini datang, jika Anda bertanya-tanya apa yang
‫terjadi, jadi tentu
‫saja pesan kesalahan ini di sini.
‫Dan itu berarti, tidak menemukan pengguna yang
‫memiliki token ini atau yang memiliki token lebih dari
‫10 menit yang lalu.
‫Jadi, memang yang ingin saya lakukan, adalah melupakan kata sandi.
‫Jadi, mari kita tunggu saja.
‫Jadi 8. 6 detik,
‫tapi itu mungkin karena koneksi internet saya.
‫Jadi jika Anda menjalankan ini
‫di server, mungkin akan jauh lebih cepat.
‫Jadi mari kita ambil itu di sini, kembali ke tukang pos, dan
‫sekarang kita mengatur ulang kata sandi, sekali lagi dengan kata sandi ini, tidak
‫masalah apakah itu sama dengan yang lama.
‫Dan, jadi sekarang kami memiliki kesuksesan kami di sini.
‫Dan sekarang kembali ke Kompas.
‫Mari kita reload, dan memang, kita mendapatkan passwordChangedAt.
‫Dan itu benar-benar terjadi sekarang.
‫Jadi, jika sekarang kita mencoba untuk benar-benar menggunakan token ini, misalnya,
‫untuk mengakses rute yang dilindungi ini, maka
‫itu akan berhasil karena tag
‫kecil, satu detik yang kita lakukan.
‫Jadi, begitulah dan seperti ini, kami sebenarnya sekarang menyelesaikan
‫Fungsi Reset Kata Sandi kami.
‫Jadi itu sedikit kode, tapi tentu saja,
‫itu sangat berharga.
‫Jadi, Anda harus selalu menawarkan
‫fungsionalitas ini di aplikasi web Anda,
‫karena jika tidak, pengguna yang lupa kata sandinya benar-benar kacau,
‫mereka tidak dapat lagi menggunakan aplikasi
‫Anda, jadi, itu tentu saja praktik yang buruk.
‫Bagaimanapun, jenis ini
‫sudah selesai, bagian otentikasi dan otorisasi dari bagian ini.
‫Jadi sekali lagi, ini
‫cukup lengkap dan saya sangat senang mengimplementasikannya.
‫Jadi, bagian ini bagi saya adalah tempat
‫aplikasi web benar-benar mulai hidup.
‫Saya tahu bahwa itu tidak benar-benar terlihat pada saat
‫ini, dengan semua ini, hanya token dan menyalin token
‫dan menempelkannya di tempat lain.
‫Itu bukan ide yang biasa kita miliki untuk masuk, saya
‫tahu, tapi tentu saja, sedikit kemudian, ketika kita
‫akhirnya mulai membangun situs web dinamis, maka tentu
‫saja kita
‫akan tetap menggunakan otentikasi yang baru saja
‫kita buat dan kemudian juga akan menjadi visual pada website dinamis tersebut.
‫Selanjutnya, kami akan mengimplementasikan fungsionalitas untuk memperbarui pengguna
‫dan juga menghapusnya, dan setelah
‫itu, kami juga akan berbicara tentang keamanan.
‫Jadi itulah yang ada di depan untuk sisa
‫bagian ini, jadi pastikan untuk tidak melewatkannya.