Аутентификация в Node.js с использованием Passport.js
В этой стаье вы узнаете, как реализовать стратегию локальной аутентификации в Node.js приложении с использованием Passport.js и Redis.
Технологии, которые мы будем использовать
Прежде чем перейти к написанию кода, давайте рассмотрим новые технологии, которые мы будем использовать в этой главе.
Что такое Passport.js?
Простая, ненавязчивая аутентификация для Node.js — passportjs.org
Passport — это middleware для проверки подлинности, которую мы собираемся использовать для управления сессиями.
Что такое Redis?
Redis это опенсорс (лицензии BSD) хранилище структур данных в оперативной памяти, используемое как база данных, кэш и брокер сообщений — redis.io
Мы собираемся хранить информацию о сессии пользователя в Redis, а не в памяти процесса. Таким образом, наше приложение будет намного проще масштабировать.
Демонстрационное приложение
Для демонстрационных целей создадим приложение, которое умеет только следующее:
- предоставляет форму входа
- предоставляет две защищённые страницы
- страницу профиля
- безопасные заметки
Структура проекта
Вы уже научились структурировать Node.js-проекты в предыдущей главе Node Hero, поэтому давайте использовать эти знания!
Мы собираемся использовать следующую структуру:
├── app
| ├── authentication
| ├── note
| ├── user
| ├── index.js
| └── layout.hbs
├── config
| └── index.js
├── index.js
└── package.json
Как вы можете видеть, мы организуем файлы и каталоги вокруг функций. У нас будет страница пользователя, страница заметок и некоторые функции, связанные с проверкой подлинности.
(Вы можете скачать исходный код по ссылке https://github.com/RisingStack/nodehero-authentication)
Процесс аутентификации в Node.js
Наша цель — реализовать в нашем приложении следующий процесс аутентификации:
- Пользователь вводит имя и пароль
- Приложение проверяет, являются ли они корректными
- Если имя и пароль корректны, приложение отправляет заголовок Set-Cookie, который будет использоваться для аутентификации дальнейших страниц
- Когда пользователь посещает страницы в том же домене, ранее установленный cookie будет добавлен ко всем запросам
- Аутентификация на закрытых страницах происходит с помощью этого файла cookie
Чтобы настроить такую стратегию аутентификации, выполните следующие три действия:
- Настройте Express
- Настройте Passport
- Добавьте защищённые разделы на сайте
Шаг 1: Настройка Express
Мы будем использовать 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.
Шаг 2: Настройка Passport
Passport — отличный пример библиотеки, использующей плагины. В этом уроке мы добавляем модуль passport-local, который добавляет простую локальную стратегию аутентификации с использованием имён пользователей и паролей.
Для простоты в этом примере (см. ниже) мы не используем базу данных, вместо неё используется экземпляр объекта пользователя в памяти. В реальных приложениях findUser будет искать пользователя в базе данных.
// file:app/authenticate/init.js
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const user = {
username: 'test-user',
password: 'test-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)).
Примечание переводчика: В настоящих приложениях стараются никогда не хранить пароли пользователей в открытом виде. В базу данных записывают хэш пароля и сравнивают его с хэшом значения, введённого пользователем.
Шаг 3: Добавляем защищённые разделы на сайте
Чтобы добавить защищенные разделы на сайт, мы используем шаблон 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: https://github.com/RisingStack/nodehero-authentication