Что такое сброс пароля?
Сброс пароля – это функция, которая помогает пользователям, которые по каким-либо причинам забыли свой пароль.
Чаще всего, чтобы сбросить пароль, пользователь просто нажимает на кнопку “забыл пароль”. Затем на адрес электронной почты пользователя будет отправлено письмо с подтверждением или токен сброса.
Это также можно сделать с помощью мобильного телефона.
В этой статье мы поговорим о том, как сбросить пароль JWT и Node.js.
Часто люди забывают свои пароли – это можно объяснить тем, что в мире Интернета повысилась безопасность, где используется несколько алгоритмов для повышения оптимальной безопасности. Это означает, что пароли должны быть надежными, а надежные пароли бывает трудно запомнить.
Кому это нужно?
На самом деле, это нужно двум категориям людей: Пользователи приложений и дизайнеры/разработчики приложений. Однако разработчики приложений должны понимать базовую структуру, которую необходимо создать для того, чтобы их приложения могли использовать эту функциональность.
В этой статье мы будем использовать существующее приложение, описанное в статье 5 шагов к аутентификации Node.js с помощью JWT. Репозиторий можно найти здесь, в ветке аутентификации.
Необходимые условия
- Уже существующее приложение.
- JWT-аутентификация.
Инструменты
Node и менеджеры пакетов
- Postman
- Bcrypts
- JWT
- Nodemailer-express-handlebars
- Nodemailer
Шаги
- Маршрут для забытого пароля.
- Настройте nodemailer для отправки шаблонов электронной почты
- Создайте шаблон электронной почты
- Метод отправки подтверждения пароля
- Маршрут для подтверждения сброса пароля.
- Метод для генерации и отправки токена на электронную почту пользователя.
Прежде чем мы продолжим, клонируйте приложение с GitHub и перейдите в ветку аутентификации.
git clone https://github.com/generalgmt/RESTfulAPITutorial git checkout authentication npm install git checkout -b password-reset
Суть приведенного выше кода заключается в том, чтобы дать нам копию кода в ветке аутентификации в новой ветке под названием “password-reset”.
Теперь, когда это сделано, мы находимся в новой ветке, где мы добавим функциональность в приложение с аутентификацией JWT
1. Маршрут для забытого пароля
В папке route откройте файл todoListRoutes.js.
Добавьте приведенный ниже фрагмент в файл:
app.route('/auth/forgot_password') .get(userHandlers.render_forgot_password_template) .post(userHandlers.forgot_password);
Маршрут get загружает шаблон, с которым пользователь должен взаимодействовать, и запрашивает сброс пароля.
Пост используется для отправки имени пользователя или адреса электронной почты, которые вы хотите сбросить.
Обработчик ‘forgot_password’ будет слушать пост-запрос на ‘/auth/forgot_password’.
2. Настройте nodemailer для отправки шаблонов электронных писем
Другими словами, чтобы отправлять электронные письма с помощью nodemailer, нам нужно его настроить.
Для удобства в этой статье мы будем использовать шаблонизатор nodemailer Handlebars.js.
var hbs = require('nodemailer-express-handlebars'), email = process.env.MAILER_EMAIL_ID || 'auth_email_address@gmail.com', pass = process.env.MAILER_PASSWORD || 'auth_email_pass' nodemailer = require('nodemailer'); var smtpTransport = nodemailer.createTransport({ service: process.env.MAILER_SERVICE_PROVIDER || 'Gmail', auth: { user: email, pass: pass } }); var handlebarsOptions = { viewEngine: 'handlebars', viewPath: path.resolve('./api/templates/'), extName: '.html' }; smtpTransport.use('compile', hbs(handlebarsOptions));
Как вы видите, я использовал метод createTransport в Nodemailer для добавления типа службы и параметров аутентификации. Ознакомьтесь с Nodemailer для получения дополнительной информации.
После этого в опции Nodemailer были добавлены движок шаблона и местоположение шаблона.
Это поможет Nodemailer узнать, какой движок использовать и где искать шаблоны.
Примечание: Если вы не используете Gmail, измените опцию сервиса в конфигурации nodemailer на имя вашего проовайдера.
3. Шаблоны электронных писем
Создайте папку под названием “templates” внутри папки api.
В этой папке создайте два HTML-файла под названием “forgot-password-email.html” и “reset-password-email.html” соответственно.
В файл “forgot-password-email” добавьте приведенный ниже фрагмент кода:
<!DOCTYPE html> <html> <head> <title>Forget Password Email</title> </head> <body> <div> <h3>Dear {{name}},</h3> <p>You requested for a password reset, kindly use this <a href="{{url}}">link</a> to reset your password</p> <br> <p>Cheers!</p> </div> </body> </html>
В файл “reset-password-email.html” вставьте приведенный ниже фрагмент кода.
<!DOCTYPE html> <html> <head> <title>Password Reset</title> </head> <body> <div> <h3>Dear {{name}},</h3> <p>Your password has been successful reset, you can now login with your new password.</p> <br/> <p>Cheers!</p> </div> </body> </html>
4. Метод отправки подтверждения пароля (forgot_password)
Этот метод будет искать существование имени пользователя/электронной почты в базе данных. Если пользователь существует, на его электронную почту будет отправлена ссылка на сброс пароля с токеном.
Async waterfall помогает убедиться, что каждая из функций выполняется одна за другой (т.е. последовательно, что часто называют синхронностью).
Первая функция в последовательности выполняет поиск пользователя в базе данных, если он существует, генерируется токен и обновляется объект пользователя в базе данных. После этого пользователю отправляется электронное письмо с маркером, который он/она должен использовать для сброса пароля.
Это служит средством подтверждения того, что вы являетесь владельцем введенного имени пользователя/электронной почты.
exports.forgot_password = function(req, res) { async.waterfall([ function(done) { User.findOne({ email: req.body.email }).exec(function(err, user) { if (user) { done(err, user); } else { done('User not found.'); } }); }, function(user, done) { // create the random token crypto.randomBytes(20, function(err, buffer) { var token = buffer.toString('hex'); done(err, user, token); }); }, function(user, token, done) { User.findByIdAndUpdate({ _id: user._id }, { reset_password_token: token, reset_password_expires: Date.now() + 86400000 }, { upsert: true, new: true }).exec(function(err, new_user) { done(err, token, new_user); }); }, function(token, user, done) { var data = { to: user.email, from: email, template: 'forgot-password-email', subject: 'Password help has arrived!', context: { url: 'http://localhost:3000/auth/reset_password?token=' + token, name: user.fullName.split(' ')[0] } }; smtpTransport.sendMail(data, function(err) { if (!err) { return res.json({ message: 'Kindly check your email for further instructions' }); } else { return done(err); } }); } ], function(err) { return res.status(422).json({ message: err }); }); };
5. Маршрут для подтверждения пароля и сброса
app.route('/auth/reset_password') .get(userHandlers.render_reset_password_template) .post(userHandlers.reset_password);
Когда пользователь, запросивший запрос пароля, нажимает на ссылку в отправленном ему письме, маршрут ‘/auth/reset_password’ отображает шаблон, с помощью которого пользователь может ввести и подтвердить новый пароль.
За этим следует AJAX-запрос к back-end на маршруте post для сохранения нового пароля.
Сниппет кода можно найти в folder/js.
6. Метод сохранения нового пароля.
Чтобы сохранить пароль, сначала необходимо выполнить несколько основных действий.
Проверить, существует ли токен в базе данных и не истек ли срок его действия.
Проверить, правильно ли введен пароль, сравнив два введенных пароля.
exports.reset_password = function(req, res, next) { User.findOne({ reset_password_token: req.body.token, reset_password_expires: { $gt: Date.now() } }).exec(function(err, user) { if (!err && user) { if (req.body.newPassword === req.body.verifyPassword) { user.hash_password = bcrypt.hashSync(req.body.newPassword, 10); user.reset_password_token = undefined; user.reset_password_expires = undefined; user.save(function(err) { if (err) { return res.status(422).send({ message: err }); } else { var data = { to: user.email, from: email, template: 'reset-password-email', subject: 'Password Reset Confirmation', context: { name: user.fullName.split(' ')[0] } }; smtpTransport.sendMail(data, function(err) { if (!err) { return res.json({ message: 'Password reset' }); } else { return done(err); } }); } }); } else { return res.status(422).send({ message: 'Passwords do not match' }); } } else { return res.status(400).send({ message: 'Password reset token is invalid or has expired.' }); } }); };
Из приведенного выше фрагмента кода следует, что если токен существует в базе данных, срок его действия не истек, а два пароля совпадают, то новый пароль будет сохранен в базе данных.
После этого пользователю отправляется электронное письмо об успешном завершении сброса пароля.
Тестирование
Для тестирования данного руководства был добавлен скелетный код front-end. Его можно найти в общей папке. Полный код здесь на GitHub – пожалуйста, сделайте ответвление на password-reset.
После клонирования и установки пакетов выполните команду “npm run start”.
В браузере перейдите на “localhost:3000”
Если вы все сделали правильно, вы должны увидеть:
и в браузере,
Нажмите на ссылку reset, и вы перейдете на новую страницу с формой для сброса пароля, как показано ниже:
Введите адрес электронной почты, по которому вы хотите сбросить пароль, и нажмите кнопку отправить.
Если электронная почта найдена в базе данных, на введенный адрес электронной почты будет отправлено письмо.
Примечание: Не забудьте добавить учетные данные электронной почты в конфигурации nodemail.
Нажмите на ссылку в электронном письме. Ссылка должна открыть новую вкладку браузера, и вам будет предложено ввести новый пароль с подтверждением.
После этого нажмите кнопку отправить. Если срок действия сгенерированного токена не истек, пароль электронной почты будет сброшен на пароль, и вы сможете войти в систему. 😃
Завершение
С помощью нескольких шагов, описанных выше, вы можете добавить функцию сброса пароля в существующее приложение Node.js.
Оригинал: “https://www.codementor.io/@olatundegaruba/password-reset-using-jwt-ag2pmlck0”