- Аутентификация в приложениях Node.js с помощью Passport
- Стратегии аутентификации
- Настройка приложения
- Добавление зависимостей проекта
- Создание модели Mongoose
- Конфигурация Mongo
- Конфигурация Passport
- Сериализация и десериализация экземпляров объекта пользователя
- Использование стратегий Passport
- Стратегия авторизации
- Стратегия регистрации
- Создание маршрутов
- Создание представлений Jade
- Реализация функции выхода из системы
- Защита маршрутов
- Заключение
- Аутентификация в Node.js с использованием Passport.js
- Node Hero: Глава 8
- Технологии, которые мы будем использовать
- Что такое Passport.js?
- Что такое Redis?
- Демонстрационное приложение
- Структура проекта
- Процесс аутентификации в Node.js
- Шаг 1: Настройка Express
- Шаг 2: Настройка Passport
- Шаг 3: Добавляем защищённые разделы на сайте
Аутентификация в приложениях Node.js с помощью Passport
Реализация надежных систем аутентификации для любого приложения может стать непростой задачей, приложение Node.js здесь не исключение.
В этой статье мы создадим с нуля Node.js приложение и используем относительно новое, но уже очень популярное связующее программное обеспечение — Passport , чтобы разобраться с проблемами аутентификации.
Позиционируясь как связующее программное обеспечение, Passport отлично справляется с тем чтобы выделить среди других элементов веб-приложений именно аспекты аутентификации.
Это позволяет Passport легко настроить любое веб-приложение на базе Express , так же, как мы можем просто настроить другой связующий Express -софт, например, logging , body-parsing , cookie-parsing , session-handling и т.д.
В этой статье мы приведем обзор базовых возможностей фреймворков Node.js и Express , при этом делая упор на вопросы аутентификации. Хотя само приложение Express мы создадим с нуля и расширим его, добавив маршруты и аутентификацию некоторых из этих маршрутов.
Стратегии аутентификации
Passport предлагает нам на выбор свыше 140 механизмов аутентификации. Вы можете проводить аутентификацию с помощью локального/удаленного экземпляра объекта базы данных или использовать единый вход с использованием OAuth , предоставляемый Facebook , Twitter , Google и т.д., для аутентификации в ваших аккаунтах социальных медиа.
Или вы можете выбрать из обширного списка провайдеров , которые поддерживают аутентификацию с помощью Passport и предоставляют для него модуль узла.
Но не беспокоитесь: Вам не нужно включать все стратегии / механизмы , которые вашему приложению и не нужны. Все эти стратегии являются независимыми друг от друга и упакованы в виде отдельных модулей узлов, которые не включаются по умолчанию при установке связующего программного обеспечения Passport : npm install passport .
В этой статье мы будем использовать локальную стратегию аутентификации Passport и аутентификацию пользователей с помощью локально настроенного экземпляра объекта Монго DB , хранящего информацию о пользователе в базе данных.
Для использования стратегии локальной аутентификации, мы должны установить модуль passport-local : npm install passport-local .
Но подождите минутку: перед тем, как вы запустите терминал и начнете выполнение этих команд, давайте все же рассмотрим построение приложения Express с нуля и добавление к нему некоторых маршрутов ( для авторизации, регистрации и главной страницы ), а затем добавим связующий софт для аутентификации.
Обратите внимание, что в этой статье мы будем использовать Express 4 , но с некоторыми незначительными отличиями Passport одинаково хорошо работает с Express 3 .
Настройка приложения
Если вы еще этого не сделали, то установите Express и express-generator для создания шаблонных приложений. Для этого нужно просто выполнить в терминале команду express passport-mongo . Сформированная структура приложения должна выглядеть следующим образом:
Добавление зависимостей проекта
Откройте файл package.json и добавьте в него зависимости для passport и модуля passport-local :
Так как мы будем сохранять информацию о пользователе в MongoDB , мы будем использовать Mongoose в качестве инструмента моделирования данных объекта. Также установить и сохранить зависимость для package.json можно с помощью команды:
package.json должен выглядеть следующим образом:
Очень скоро мы это изменим, создав полноценное Express приложение, которое запрашивает вывод страницы регистрации для нового пользователя, обрабатывает вход в систему зарегистрированного пользователя и аутентифицирует зарегистрированного пользователя, используя Passport .
Создание модели Mongoose
Так как мы будем сохранять информацию о пользователях в Mongo , давайте создадим модель пользователя в Mongoose и сохраним ее в файле models/user.js нашего приложения:
Мы создаем модель Mongoose , с помощью которой мы можем выполнять CRUD операции в основной базе данных.
Конфигурация Mongo
Если у вас нет установленного локально Mongo , мы рекомендуем использовать облачные сервисы баз данных, такие как Modulus или MongoLab .
Создание рабочего экземпляра MongoDB с их помощью не только бесплатно, но кроме того это можно сделать всего лишь в несколько кликов.
После создания базы данных на одном из этих сервисов, вы получите URI базы данных, наподобие mongodb://:@novus.modulusmongo.net:27017/, который можно использовать для выполнения CRUD -операций с базой данных.
Я рекомендую сохранить конфигурацию базы данных в отдельный файл, который можно будет подтянуть, когда это будет необходимо. Таким образом, мы создаем модуль узла db.js , который выглядит следующим образом:
Теперь мы используем эту конфигурацию в app.js и подключаемся к ней с помощью Mongoose API :
Конфигурация Passport
Passport только обеспечивает механизм для обработки аутентификации, не заботясь о реализации обработки своей же сессии, для этого мы будем использовать express-session .
Откройте файл app.js и вставьте перед настройкой маршрутов приведенный ниже код:
Это необходимо, поскольку мы хотим, чтобы сеансы пользователей были стабильными. Перед запуском приложения мы должны установить express-session и добавить его в список зависимостей файла package.json . Для этого наберите в командной строке — npm install —save express-session .
Сериализация и десериализация экземпляров объекта пользователя
Для Passport также необходима сериализация и десериализация экземпляра объекта пользователя из сессии сохранения в целях поддержки текущей сессии, так чтобы каждый последующий запрос не содержал учетные данные пользователя. Для этого предназначены два метода serializeUser и deserializeUser :
Использование стратегий Passport
Теперь мы определим стратегии Passport для обработки авторизации и регистрации. Каждая из них будет экземпляром стратегии локальной аутентификации Passport и будет создаваться при помощи функции passport.use() .
Мы используем connect-flash , что поможет нам в обработке ошибок, предоставляя флэш-сообщения, которые могут выводиться пользователю при возникновении ошибки.
Стратегия авторизации
Стратегия авторизации выглядит следующим образом:
Первый параметр passport.use() является именем стратегии, которое будет использоваться для идентификации этой стратегии при последующем применении. Вторым параметром является тип стратегии, которую вы хотите создать, здесь мы используем username-password или LocalStrategy .
Следует отметить, что по умолчанию LocalStrategy ищет учетные данные пользователя в параметрах username и password , но мы можем также использовать любые другие проименованные параметры.
Переменная конфигурации passReqToCallback позволяет нам получить доступ к объекту request в функции обратного вызова, благодаря чему, в свою очередь, мы имеем возможность использовать любой параметр, связанный с запросом.
Далее, мы используем Mongoose API , чтобы найти пользователя в нашей основной базе пользователей и проверить, является ли он доверенным пользователем или нет.
Последний параметр в нашем обратном вызове done указывает на используемый метод, с помощью которого мы сообщаем модулю Passport об успешном выполнении действия или ошибке.
Чтобы идентифицировать сбой либо первый параметр должен содержать ошибку, либо второй параметр должен содержать значение false . Для обозначения успешного прохождения действия первый параметр должен иметь значение null , а второй — truthy , в этом случае объект request становится доступен.
Поскольку пароли по своей природе являются уязвимым местом, мы всегда должны шифровать их перед сохранением в базу данных. Для этого мы используем bcrypt-nodejs , который помогает шифровать и расшифровывать пароли:
Если вам неудобно работать с отдельными фрагментами кода, и вы предпочитают видеть полный код в действии, вы можете просмотреть его здесь .
Стратегия регистрации
Теперь мы определяем следующую стратегию, которая будет обрабатывать регистрацию нового пользователя и создавать его учетную запись в основной базе данных Mongo DB :
Здесь мы снова использовали Mongoose API , чтобы выяснить, существует ли пользователь с данным именем пользователя или нет. Если нет, то создаем нового пользователя и сохраняем информацию о нем в Mongo .
В противном случае возвращаем ошибку с помощью обратного вызова done и флэш-сообщения. Обратите внимание, что мы используем bcrypt-nodejs для создания хэша пароля перед его сохранением:
Создание маршрутов
В общем, схема нашего приложения будет выглядеть так:
Наиболее важной частью приведенного выше фрагмента кода является использование passport.authenticate() для делегирования аутентификации стратегиям login и signup , когда HTTP POST выполнен для маршрутов /login и /signup соответственно.
Обратите внимание, что не обязательно называть стратегии соответственно пути маршрута, им можно назначать произвольные имена.
Создание представлений Jade
Далее, мы создаем следующие два представления для нашего приложения:
- layout.jade — содержит базовую структуру и информацию о стилях;
- index.jade — содержит страницу авторизации, включающую форму входа и опции для создания новой учетной записи:
Благодаря Bootstrap наша страница авторизации теперь выглядит следующим образом:
- register.jade — содержит форму регистрации;
- home.jade — выводит приветствие и данные авторизовавшегося пользователя.
Если вы не работали с Jade , здесь можете найти документацию по нему.
Реализация функции выхода из системы
Passport , будучи связующим софтом, позволяет добавлять определенные свойства и методы к объектам запросов и ответов, что в свою очередь дает возможность добавить очень удобный метод request.logout() , который отменяет сеанс пользователя:
Защита маршрутов
Passport также предоставляет возможность защитить доступ к маршруту, который не предназначен для анонимных пользователей.
Это означает, что если некоторые пользователи пытается получить доступ к маршруту http://localhost:3000/home без авторизации в системе, они будут перенаправлены на главную страницу следующим образом:
Заключение
Passport не является единственным возможным решением, когда речь заходит об аутентификации приложений Node.js , существуют и альтернативные варианты, такие как EveryAuth .
Но большое количество модулей, гибкость, поддержка сообщества и тот факт, что он является просто связующим программным обеспечением, действительно выделяет Passport из череды других приложений.
Аутентификация в Node.js с использованием Passport.js
Node Hero: Глава 8
Перевод книги Node Hero от RisingStack . Переведено с разрешения правообладателей.
В этой главе вы узнаете, как реализовать стратегию локальной аутентификации в Node.js приложении с использованием Passport.js и Redis.
Технологии, которые мы будем использовать
Прежде чем перейти к написанию кода, давайте рассмотрим новые технологии, которые мы будем использовать в этой главе.
Что такое Passport.js?
Простая, ненавязчивая аутентификация для Node.js — passportjs.org
Passport — это middleware для проверки подлинности, которую мы собираемся использовать для управления сессиями.
Что такое Redis?
Redis это опенсорс (лицензии BSD) хранилище структур данных в оперативной памяти, используемое как база данных, кэш и брокер сообщений — redis.io
Мы собираемся хранить информацию о сессии пользователя в Redis, а не в памяти процесса. Таким образом, наше приложение будет намного проще масштабировать.
Демонстрационное приложение
Для демонстрационных целей создадим приложение, которое умеет только следующее:
- предоставляет форму входа
- предоставляет две защищённые страницы:
- страницу профиля
- безопасные заметки
Структура проекта
Вы уже научились структурировать Node.js-проекты в предыдущей главе Node Hero, поэтому давайте использовать эти знания!
Мы собираемся использовать следующую структуру:
Как вы можете видеть, мы организуем файлы и каталоги вокруг функций. У нас будет страница пользователя, страница заметок и некоторые функции, связанные с проверкой подлинности.
Процесс аутентификации в Node.js
Наша цель — реализовать в нашем приложении следующий процесс аутентификации:
- Пользователь вводит имя и пароль
- Приложение проверяет, являются ли они корректными
- Если имя и пароль корректны, приложение отправляет заголовок Set-Cookie , который будет использоваться для аутентификации дальнейших страниц
- Когда пользователь посещает страницы в том же домене, ранее установленный cookie будет добавлен ко всем запросам
- Аутентификация на закрытых страницах происходит с помощью этого файла cookie
Чтобы настроить такую стратегию аутентификации, выполните следующие три действия:
- Настройте Express
- Настройте Passport
- Добавьте защищённые разделы на сайте
Шаг 1: Настройка Express
Мы будем использовать Express для серверной среды — вы можете узнать больше на эту тему, перечитав главу «Ваш первый сервер на Node.js».
Что мы тут делаем?
Прежде всего, нам нужны все зависимости, которые требуются для управления сессией. После этого мы создали новый экземпляр из модуля express-session , который будет хранить наши сессии.
Для хранения сессий мы используем Redis, но вы можете использовать любые другие, такие как MySQL или MongoDB.
Шаг 2: Настройка Passport
Passport — отличный пример библиотеки, использующей плагины. В этом уроке мы добавляем модуль passport-local , который добавляет простую локальную стратегию аутентификации с использованием имён пользователей и паролей.
Для простоты в этом примере (см. ниже) мы не используем базу данных, вместо неё используется экземпляр объекта пользователя в памяти. В реальных приложениях findUser будет искать пользователя в базе данных.
Как только findUser возвращается с нашим объектом пользователя, остаётся только сравнить введённый пользователем и реальный пароль, чтобы увидеть, есть ли совпадение.
Если они совпадают, мы разрешаем пользователю войти (возвращая объект пользователь в passport — return done(null, user) ), если нет — возвращаем ошибку авторизации(путём возврата null — return done(null) ).
Примечание переводчика: В настоящих приложениях стараются никогда не хранить пароли пользователей в открытом виде. В базу данных записывают хэш пароля и сравнивают его с хэшом значения, введённого пользователем.
Шаг 3: Добавляем защищённые разделы на сайте
Чтобы добавить защищенные разделы на сайт, мы используем шаблон middleware Express. Для этого сначала создадим middleware для аутентификации:
Она имеет только одну задачу — если пользователь аутентифицирован (имеет правильные cookie-файлы), она просто вызывает следующую middleware. В противном случае пользователь перенаправляется на страницу, где он может войти в систему.
Использование этой middleware также просто, как добавление любой другой middleware в определение роута.