Ukrainian (українська мова) translation by AlexBioJS (you can also view the original English article)
Вступ
Так само як аутентифікація важлива для API (* Application Programming Interface - інтерфейс прикладних програм. Тут і надалі примітка перекладача), вона є важливою особливістю певних веб-застосунків - тих, у котрих є сторінки та секрети, до яких повинен бути доступ тільки для користувачів, що пройшли реєстрацію та аутентифікацію.
У цьому посібнику в процесі вивчення реалізації реєстрації користувачів ви створите веб-додаток.
Встановлення застосунку
Створіть нову папку, в якій ви будете працювати. Згідно з темою цього посібника я назвав мою site-auth. Ініціалізуйте проект у тільки-но створеній папці. Нижче наведено, як ви можете це зробити.
npm init -y
Фдаг -y
повідомляє npm (* пакетний менеджер для JavaScript) про необхідність використання опцій за налаштуванням.
Відредагуйте частину файлу package.json таким чином, щоб вона виглядала, як моя.
#package.json { "name": "site-auth", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "izuchukwu1", "license": "ISC", "dependencies": { "bcryptjs": "^2.4.3", "body-parser": "^1.17.1", "connect-flash": "^0.1.1", "cookie-parser": "^1.4.3", "express": "^4.15.2", "express-handlebars": "^3.0.0", "express-messages": "^1.0.1", "express-session": "^1.15.2", "joi": "^13.0.1", "mongoose": "^4.11.12", "morgan": "^1.8.1", "passport": "^0.4.0", "passport-local": "^1.0.0" } }
Після цього запустіть команду для встановлення пакетів.
npm install
Створіть файл у вашій робочій папці під назвою app.js.
Почніть із запиту залежностей, що ви встановили, та необхідних файлів.
#app.js const express = require('express'); const morgan = require('morgan') const path = require('path'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const expressHandlebars = require('express-handlebars'); const flash = require('connect-flash'); const session = require('express-session'); const mongoose = require('mongoose') const passport = require('passport') require('./config/passport')
Ці залежності було встановлено після виконання команди npm install. Для того щоб їх використовувати у вашому додатку, вам необхідно запитати та зберегти їх до відповідних констант.
У цьому посібнику ви будете використовувати у якості бази даних MongoDB. Вам необхідно буде зберегти інформацію про користувача до бази даних. Для роботи з MongoDB ви будете використовувати Mongoose - інструмент для модулювання в Node.js (* ODM (Object Document Mapper - об'єктно-документний відображувач)). Налаштування Mongoose не викликає труднощів. Виконується наступним чином:
#app.js mongoose.Promise = global.Promise mongoose.connect('mongodb://localhost:27017/site-auth')
На цьому етапі давайте налаштуємо наше ПЗ проміжного шару (* програмне забезпечення).
// 1 const app = express() app.use(morgan('dev')) // 2 app.set('views', path.join(__dirname, 'views')) app.engine('handlebars', expressHandlebars({ defaultLayout: 'layout' })) app.set('view engine', 'handlebars') // 3 app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: false })) app.use(cookieParser()) app.use(express.static(path.join(__dirname, 'public'))) app.use(session({ cookie: { maxAge: 60000 }, secret: 'codeworkrsecret', saveUninitialized: false, resave: false })); app.use(passport.initialize()) app.use(passport.session()) // 4 app.use(flash()) app.use((req, res, next) => { res.locals.success_mesages = req.flash('success') res.locals.error_messages = req.flash('error') next() }) // 5 app.use('/', require('./routes/index')) app.use('/users', require('./routes/users')) // 6 // catch 404 and forward to error handler app.use((req, res, next) => { res.render('notFound') }); // 7 app.listen(5000, () => console.log('Server started listening on port 5000!'))
- Результат ініціалізації Express присвоюється константі
app
. - Відбувається налаштування ПЗ проміжного шару, що буде займатися представленнями. Для створення представлень ви будете використовувати
handlebars
. - Ви налаштували ПЗ проміжного шару для
bodyparser
,cookie
,session
таpassport
. Passport буде використовуватися, коли користувачі хочуть увійти до застосування. - У певні моменти ви будете відображувати флеш-повідомлення. Тому вам необхідно налаштувати ПЗ проміжного шару для цього та створити необхідний вам тип флеш-повідомлення.
- ПЗ проміжного шару для налаштування маршрутів. Буде опрацьовувати будь-який запит, зроблений по шляху URL (* Uniform Resource Locator - уніфікований покажчик [місцезнаходження інформаційного] ресурсу). Тут вказано шляхи URL для шляхів, що вказані у файлах index та users.
- ПЗ проміжного шару для обробки помилок 404. Це ПЗ проміжного шару починає діяти, якщо запит не відповідає жодному з вищезазначених ПЗ проміжного шару.
- Сервер налаштовується на прослуховування запитів по 5000 порту.
Налаштування представлень
Створіть нову папку під назвою views (* представлення). Усередині створіть дві інші папки під назвами layouts та partials. Сформуйте необхідну деревоподібну структуру у папці views. Для цього створіть необхідні файли в їх відповідних папках.
├── dashboard.handlebars ├── index.handlebars ├── layouts │ └── layout.handlebars ├── login.handlebars ├── notFound.handlebars ├── partials │ └── navbar.handlebars └── register.handlebars
Після цього настав час писати код.
#dashboard.handlebars <!-- Jumbotron --> <div class="jumbotron"> <h1>User DashBoard</h1> </div>
Це - приладова панель, яку повинно бути видно тільки зареєстрованим користувачам. У цьому посібнику це буде наша секретна сторінка.
Далі переходимо до сторінки додатка index, яка повинна виглядати наступним чином:
#index.handlebars <!-- Jumbotron --> <div class="jumbotron"> <h1>Site Authentication!</h1> <p class="lead">Welcome aboard.</p> </div>
Для застосунку потрібен макет. Нижче наведено макет, який будете використовувати.
#layout/layout.handlebars <!DOCTYPE html> <html> <head> <title>Site Authentication</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> <link rel="stylesheet" href="/css/style.css"> </head> <body> {{#if success_messages }} <div class="alert alert-success">{{success_messages}}</div> {{/if}} {{#if error_messages }} <div class="alert alert-danger">{{error_messages}}</div> {{/if}} <div class="container"> {{> navbar}} {{{body}}} </div> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> </body> </html>
Вам знадобиться сторінка входу для зареєстрованих користувачів.
#views/login.handlebars <form class="form-signin" action="/users/login" method="POST"> <h2 class="form-signin-heading">Please sign in</h2> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" id="inputEmail" name="email" class="form-control" placeholder="Email address" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required> <br/> <button class="btn btn-lg btn-default btn-block" type="submit">Sign in</button> </form>
Файл notFound.handlebars буде використовуватися у якості сторінки для показу помилок.
#views/notFound.handlebars <!-- Jumbotron --> <div class="jumbotron"> <h1>Error</h1> </div>
Ваша сторінка для реєстрації повинна виглядати наступним чином.
<form class="form-signin" action="/users/register" method="POST"> <h2 class="form-signin-heading">Please sign up</h2> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" id="inputEmail" name="email" class="form-control" placeholder="Email address" required autofocus> <label for="inputUsername" class="sr-only">Username</label> <input type="text" id="inputUsername" name="username" class="form-control" placeholder="Username" required> <label for="inputPassword" class="sr-only">Password</label> <input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required> <label for="inputConfirmPassword" class="sr-only">Confirm Password</label> <input type="password" id="inputConfirmPassword" name="confirmationPassword" class="form-control" placeholder="Confirm Password" required> <br/> <button class="btn btn-lg btn-default btn-block" type="submit">Sign up</button> </form>
Останній файл для ваших представлень із кодом навігаційної панелі наведено нижче.
#partials/navbar.handlebars <div class="masthead"> <h3 class="text-muted">Site Authentication</h3> <nav> <ul class="nav nav-justified"> <li class="active"><a href="/">Home</a></li> {{#if isAuthenticated}} <li><a href="/users/dashboard">Dashboard</a></li> <li><a href="/users/logout">Logout</a></li> {{else}} <li><a href="/users/register">Sign Up</a></li> <li><a href="/users/login">Sign In</a></li> {{/if}} </ul> </nav> </div>
Після цього ви готові до розгляду деяких складних частин застосунку.
Перевірка даних
Вам необхідна буде модель User. Виходячи з коду для представлень вище ви можете зробити висновок, що для моделі User необхідні властивості email, username і password. Створіть папку під назвою models та файл у ній під назвою user.js.
#models/user.js // 1 const mongoose = require('mongoose') const Schema = mongoose.Schema const bcrypt = require('bcryptjs') // 2 const userSchema = new Schema({ email: String, username: String, password: String }, { // 3 timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' } }) // 4 const User = mongoose.model('user', userSchema) module.exports = User
- Відбувається імпорт залежностей та їх зберігання до констант.
- Створюється нова схема. Для кожного користувача ви зберігаєте
адресу електронної пошти
,ім'я
тапароль
до бази даних. Схема описує, як повинно бути створено модель для кожного документа. Тут ви зазначаєте, що типом адреси електронної пошти, імені користувача та пароля повинен бути String. - Також для кожного користувача ви хочете створити
timestamps
(* час створення/модифікації файлу). Ви використовуєте Mongoose для отримання значеньcreatedAt
таupdatedAt
. Потім зберігаєте їх до бази даних. - Визначається модель, и результат присвоюється константі під назвою
User
, яка потім експортується як модуль. Через це її можна використовувати в інших частинах додатка.
Підсоювання та гешування пароля
Не варто зберігати паролі користувачів у незашифрованому вигляді. Ось що потрібно зробити, коли користувач уводить пароль у незашифрованому вигляді під час реєстрації. Пароль у незашифрованому вигляді повен бути загешован за допомогою солі (* у криптографії - випадкове число чи текст, що додаються до даних, що шифруються за допомогою пароля), що буде згенеровано вашим застосунком (використовуючи модуль bcryptjs). Цей загешований пароль потім зберігається їх до бази даних.
Звучить чудово, чи не так? Давайте реалізуємо це в файлі user.js.
#models/user.js module.exports.hashPassword = async (password) => { try { const salt = await bcrypt.genSalt(10) return await bcrypt.hash(password, salt) } catch(error) { throw new Error('Hashing failed', error) } }
Ви тільки-но створили метод, який буде викликано під час реєстрації користувача. До методу передається незашифрований пароль, уведений користувачем. Як я згадував раніше, пароль у незашифрованому вигляді повен бути загешован за допомогою солі, яку буде згенеровано вашим застосуванням. Загешований пароль буде повернуто як пароль для користувача.
Маршрути Index и Users
Створіть нову папку під назвою routes. У цій новій папці створіть два нових файли: index.js та users.js.
Файл index.js буде дуже простим. У ньому буде викликатися на виконання представлення index вашого застосунку. Пам'ятаєте, як ви налаштували ПЗ проміжного шару для ваших маршрутів у вашому файлі app.js, коли ви зробили наступне:
app.use('/', require('./routes/index')) app.use('/users', require('./routes/users'))
Отже, ваш маршрут у файлі index.js, що просто виконує сторінку index, повинен виглядати наступним чином:
#routes/index.js const express = require('express') const router = express.Router() router.get('/', (req, res) => { res.render('index') }) module.exports = router
Тепер переходимо до маршруту users. Поки що в цьому файлі для маршруту будуть виконуватися чотири дії:
- Запит залежностей. Вам необхідно буде запросити залежності, які ви встановили за допомогою npm.
- Перевірка даних користувача. Впевніться, що користувач не надіслав порожню форму. Усі поля повинні бути заповнені. Адреса електронної пошти спеціально перевіряється за допомогою методу
.email()
, завдяки якому гарантується, що уведені користувачем дані відповідають формату адреси електронної пошти. Пароль же перевіряється за допомогою регулярного виразу. У паролі підтвердження варто зберегти те ж значення, що й в уведеному паролі. Ці перевірки здійснюються за допомогою модуля Joi. - Встановлення вашого маршрутизатора. При надходженні запитів по методу GET виконується сторінка реєстрації, тим часом як запити по методу POST надходять після того, як користувач натискає кнопку для відправлення форми.
- Маршрутизатор експортується у вигляді модуля.
Ось як виглядає код.
#routes/users.js const express = require('express'); const router = express.Router() const Joi = require('joi') const passport = require('passport') const User = require('../models/user') //validation schema const userSchema = Joi.object().keys({ email: Joi.string().email().required(), username: Joi.string().required(), password: Joi.string().regex(/^[a-zA-Z0-9]{6,30}$/).required(), confirmationPassword: Joi.any().valid(Joi.ref('password')).required() }) router.route('/register') .get((req, res) => { res.render('register') }) .post(async (req, res, next) => { try { const result = Joi.validate(req.body, userSchema) if (result.error) { req.flash('error', 'Data entered is not valid. Please try again.') res.redirect('/users/register') return } const user = await User.findOne({ 'email': result.value.email }) if (user) { req.flash('error', 'Email is already in use.') res.redirect('/users/register') return } const hash = await User.hashPassword(result.value.password) delete result.value.confirmationPassword result.value.password = hash const newUser = await new User(result.value) await newUser.save() req.flash('success', 'Registration successfully, go ahead and login.') res.redirect('/users/login') } catch(error) { next(error) } }) module.exports = router
Давайте розглянемо більш детально, що відбувається при надходженні запитів по методу POST.
Значення, уведені в формі для реєстрації, доступні через властивість req.body
та мають наступний вигляд:
value: { email: 'chineduizuchkwu1@gmail.com', username: 'izu', password: 'chinedu', confirmationPassword: 'chinedu' },
Ця властивість перевіряється за допомогою схеми userSchema
, що ви створили раніше. Уведені користувачем значення присвоюються константі під назвою result.
У випадку помилки під час перевірки даних повідомлення про помилку відображається користувачеві та відбувається переадресація користувача на сторінку реєстрації.
Інакше ми намагаємося встановити, чи існує користувач із тією ж адресою електронної пошти, оскільки нам не хотілося б мати двох чи більше користувачів із однаковою адресою.
У випадку співпадання адреси електронної пошти користувач інформується, що його адреса вже використовується. Інакше наступним етапом є гешування пароля. У цей час ви й викликаєте метод hashPassword
, який визначили у вашому файлі user.js. Новий загешований пароль присвоюється константі hash.
Нема необхідності у зберіганні confirmationPassword
до бази даних. Тому ця властивість видаляється. Доступний у змінній пароль досі незашифрован. Оскільки не варто зберігати незашифрований пароля до вашої бази даних, важливо знову присвоїти в якості значення пароля створений геш. Це здійснюється за допомогою наступного рядка коду:
result.value.password = hash
Екземпляр нового користувача зберігається до бази даних. Виводиться флеш-повідомлення, яке оповіщає, що реєстрація пройшла вдало, і користувач переадресовується на сторінку входу до застосування.
Запустіть ваш сервер, виконавши в консолі команду:
node app.js
Перейдіть у вашому браузері на сторінку http://localhost:5000, і ви повинні будете побачити ваш новий додаток.
Завершення
Тепер ви знаєте, як реалізувати можливість реєстрації в Node-застосунках. Ви зрозуміли важливість перевірки користувальницьких даних та процес її здійсТакож ви використали модуль bcryptjs
для підсолювання та гешування вашого пароля.нення за допомогою Joi.
Далі ви дізнаєтеся, як реалізувати можливість входу до системи для зареєстрованих користувачів. Сподіваюсь, що матеріал вам сподобався!
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weekly