Перевод книги Node Hero от RisingStack. Переведено с разрешения правообладателей.
В этой главе вы узнаете, как реализовать стратегию локальной аутентификации в Node.js приложении с использованием Passport.js и Redis.
Прежде чем перейти к написанию кода, давайте рассмотрим новые технологии, которые мы будем использовать в этой главе.
Простая ненавязчивая аутентификация для Node.js - passportjs.org
Passport.js - это middleware для проверки подлинности. Мы будем исполььзовать её для управления сессиями.
Redis это опенсорс (лицензии BSD) хранилище структур данных в оперативной памяти, используемое как база данных, кэш и брокер сообщений — redis.io
Мы собираемся хранить информацию о сессии пользователя в Redis, а не в памяти процесса. Таким образом, наше приложение будет намного проще масштабировать.
Для демонстрационных целей создадим приложение, которое умеет только следующее:
- предоставляет форму входа
- предоставляет две защищённые страницы:
- страницу профиля
- безопасные заметки
Вы уже научились структурировать Node.js-проекты в предыдущей главе Node Hero, поэтому давайте использовать эти знания!
Мы собираемся использовать следующую структуру:
├── app
| ├── authentication
| ├── note
| ├── user
| ├── index.js
| └── layout.hbs
├── config
| └── index.js
├── index.js
└── package.json
Как вы можете видеть, мы организуем файлы и каталоги вокруг функций. У нас будет страница пользователя, страница заметок и некоторые функции, связанные с проверкой подлинности.
(Вы можете скачать исходный код по ссылке)
Наша цель - реализовать в нашем приложении следующий процесс аутентификации:
- Пользователь вводит имя и пароль
- Приложение проверяет, являются ли они корректными
- Если имя и пароль корректны, приложение отправляет заголовок
Set-Cookie
, который будет использоваться для аутентификации дальнейших страниц - Когда пользователь посещает страницы в том же домене, ранее установленный cookie добавляется ко всем запросам
- Аутентификация на закрытых страницах происходит с помощью этого файла cookie
Чтобы настроить такую стратегию аутентификации, выполните следующие три действия:
- Настройте Express
- Настройте Passport
- Добавьте защищённые разделы на сайте
Мы будем использовать Express для серверной среды. Вы можете узнать больше на эту тему, перечитав главу «Ваш первый сервер на Node.js».
// file:app/index.js
const express = require('express')
const passport = require('passport')
const session = require('express-session')
const RedisStore = require('connect-redis')(session)
const app = express()
app.use(session({
store: new RedisStore({
url: config.redisStore.url
}),
secret: config.redisStore.secret,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
Что мы тут делаем?
Прежде всего, нам нужны все зависимости, требующиеся для управления сессией. После этого мы создали новый экземпляр из модуля express-session
, который будет хранить наши сессии.
Для хранения сессий мы используем Redis, но вы можете использовать любые другие, такие как MySQL или MongoDB.
Passport.js — отличный пример библиотеки, использующей плагины. В этом уроке мы добавляем модуль passport-local
, который добавляет простую локальную стратегию аутентификации с использованием имён пользователей и паролей.
Для простоты в этом примере (см. ниже) мы не используем базу данных, вместо неё используется экземпляр объекта пользователя в памяти. В реальных приложениях findUser
будет искать пользователя в базе данных.
file:app/authenticate/init.js
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const user = {
username: 'test-user',
password: 'my-password',
id: 1
}
passport.use(new LocalStrategy(
function(username, password, done) {
findUser(username, function (err, user) {
if (err) {
return done(err)
}
if (!user) {
return done(null, false)
}
if (password !== user.password ) {
return done(null, false)
}
return done(null, user)
})
}
))
Как только findUser возвращается с нашим объектом пользователя, остаётся только сравнить введённый пользователем и реальный пароли, чтобы увидеть, есть ли совпадение.
Если они совпадают, мы разрешаем пользователю войти (возвращая объект пользователя в passport
- return done(null, user)
), если нет — возвращаем ошибку авторизации (путём возврата null
- return done(null)
).
Примечание переводчика: в настоящих приложениях стараются никогда не хранить пароли пользователей в открытом виде. В базу данных записывают хэш пароля и сравнивают его с хэшом значения, введённого пользователем.
Чтобы добавить защищенные разделы на сайт, мы используем шаблон middleware Express. Для этого сначала создадим middleware для аутентификации:
// file:app/user/init.js
const passport = require('passport')
app.get('/profile', passport.authenticationMiddleware(), renderProfile)
Она имеет только одну задачу: если пользователь аутентифицирован (имеет правильные cookie-файлы), она просто вызывает следующую middleware. В противном случае пользователь перенаправляется на страницу, где он может войти в систему.
Использование этой middleware также просто, как добавление любой другой middleware в определение роута.
// file:app/authentication/middleware.js
function authenticationMiddleware () {
return function (req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/')
}
}
В этом разделе учебника по Node.js вы узнали, как добавить базовую аутентификацию в ваше приложение. Позже вы можете расширить его с помощью различных стратегий аутентификации, таких как Facebook или Twitter. Вы можете найти больше стратегий по адресу http://passportjs.org/.
Полный рабочий пример нашего демонстрационного приложения вы можете найти на GitHub.
Следующая глава Node Hero будет посвящена юнит-тестированию Node.js приложений. Вы узнаете такие концепции, как юнит-тестирование, пирамида тестирования, дублёры и многое другое!
Слушайте наш подкаст в iTunes и SoundCloud, читайте нас на Medium, контрибьютьте на GitHub, общайтесь в группе Telegram, следите в Twitter и канале Telegram, рекомендуйте в VK и Facebook.