Node.js: шаблон сервера для аутентификации и авторизации / хабр

Вступление

В этой статье мы поговорим о том, как работают JSON Web Tokens, каковы
их преимущества, их структура и как их использовать для обработки
базовой аутентификации и авторизации в Express.

Вам не обязательно иметь опыт работы с веб-токенами JSON, поскольку мы
будем говорить об этом с нуля.

Для раздела реализации было бы предпочтительнее, если у вас есть
предыдущий опыт работы с Express , Javascript
ES6 и клиентами REST.

Что такое веб-токены json?

Веб-токены JSON (JWT) были введены как метод безопасного обмена
данными между двумя сторонами. Он был представлен со спецификацией RFC
7519Инженерной группой
Интернета (IETF).

Upd1:

Недавно столкнулся с задачей задать несколько стратегий авторизации на один роут. Как выяснилось, это можно сделать, передав массив строк в функцию авторизации:

app.post('/test', passport.authenticate(['simple-jwt', 'jwt'], { session: false }), (req, res) => { ...

При этом, все стратегии применяются с условием логическое ИЛИ. Срабатывает первая из удачных стратегий. Если произошла ошибка, и ее обработали функцией done(err), то дальше авторизация не проходит. Поэтому во всех стратегиях, кроме последней в списке авторизации, ошибка должна обрабтываться вызовом done(null, false).

Upd2:

Если у Вас не нашлось подходящей стратегии — в качестве конструктора новых стратегий можно использовать стратегию passport-custom:

Аутентификация в приложениях node.js с помощью passport

Реализация надежных систем аутентификации для любого приложения может стать непростой задачей, приложение Node.js здесь не исключение.

В этой статье мы создадим с нуля Node.js приложение и используем относительно новое, но уже очень популярное связующее программное обеспечение – Passport, чтобы разобраться с проблемами аутентификации.

Документация Passport описывает его как “простое, компактное связующее приложение аутентификации для Node” и это верно.

Позиционируясь как связующее программное обеспечение, 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. Сформированная структура приложения должна выглядеть следующим образом:

Давайте удалим некоторый функционал по умолчанию, который нам вовсе необязательно использовать – удалите маршрут users.js и уберите все его ссылки из файла app.js.

Откройте файл package.json и добавьте в него зависимости для passport и модуля passport-local:

Так как мы будем сохранять информацию о пользователе в MongoDB, мы будем использовать Mongoose в качестве инструмента моделирования данных объекта. Также установить и сохранить зависимость для package.json можно с помощью команды:

package.json должен выглядеть следующим образом:

Теперь установите все зависимости и запустите шаблонное приложение, выполнив команду npm install && npm start. Она загружает и устанавливает все зависимости и запускает сервер узла. Вы можете проверить установку приложения Express, перейдя по адресу: http://localhost:3000/, но там вы пока еще ничего особенного не увидите.

Очень скоро мы это изменим, создав полноценное Express приложение, которое запрашивает вывод страницы регистрации для нового пользователя, обрабатывает вход в систему зарегистрированного пользователя и аутентифицирует зарегистрированного пользователя, используя Passport.

Так как мы будем сохранять информацию о пользователях в Mongo, давайте создадим модель пользователя в Mongoose и сохраним ее в файле models/user.js нашего приложения:

Мы создаем модельMongoose, с помощью которой мы можем выполнять CRUD операции в основной базе данных.

Если у вас нет установленного локально Mongo, мы рекомендуем использовать облачные сервисы баз данных, такие как Modulus или MongoLab.

Создание рабочего экземпляра MongoDB с их помощью не только бесплатно, но кроме того это можно сделать всего лишь в несколько кликов.

После создания базы данных на одном из этих сервисов, вы получите URI базы данных, наподобие mongodb://:@novus.modulusmongo.net:27017/, который можно использовать для выполнения CRUD-операций с базой данных.

Я рекомендую сохранить конфигурацию базы данных в отдельный файл, который можно будет подтянуть, когда это будет необходимо. Таким образом, мы создаем модуль узла db.js, который выглядит следующим образом:

Теперь мы используем эту конфигурацию в app.js и подключаемся к ней с помощью Mongoose API:

Passport только обеспечивает механизм для обработки аутентификации, не заботясь о реализации обработки своей же сессии, для этого мы будем использовать express-session.

Откройте файл app.js и вставьте перед настройкой маршрутов приведенный ниже код:

Это необходимо, поскольку мы хотим, чтобы сеансы пользователей были стабильными. Перед запуском приложения мы должны установить express-session и добавить его в список зависимостей файла package.json. Для этого наберите в командной строке – npm install –save express-session.

Для Passport также необходима сериализация и десериализация экземпляра объекта пользователя из сессии сохранения в целях поддержки текущей сессии, так чтобы каждый последующий запрос не содержал учетные данные пользователя. Для этого предназначены два метода serializeUser и deserializeUser:

Теперь мы определим стратегии Passport для обработки авторизации и регистрации. Каждая из них будет экземпляром стратегии локальной аутентификации Passport и будет создаваться при помощи функции passport.use().

Мы используем connect-flash, что поможет нам в обработке ошибок, предоставляя флэш-сообщения, которые могут выводиться пользователю при возникновении ошибки.

Стратегия авторизации выглядит следующим образом:

// passport/login.js
passport.use('login', new LocalStrategy({
    passReqToCallback : true
  },
  function(req, username, password, done) { 
    // проверка в mongo, существует ли пользователь с таким логином
    User.findOne({ 'username' :  username }, 
      function(err, user) {
        // В случае возникновения любой ошибки, возврат с помощью метода done
        if (err)
          return done(err);
        // Пользователь не существует, ошибка входа и перенаправление обратно
        if (!user){
          console.log('User Not Found with username ' username);
          return done(null, false, 
                req.flash('message', 'User Not found.'));                 
        }
        // Пользователь существует, но пароль введен неверно, ошибка входа 
        if (!isValidPassword(user, password)){
          console.log('Invalid Password');
          return done(null, false, 
              req.flash('message', 'Invalid Password'));
        }
        // Пользователь существует и пароль верен, возврат пользователя из 
        // метода done, что будет означать успешную аутентификацию
        return done(null, user);
      }
    );
}));

Первый параметр passport.use() является именем стратегии, которое будет использоваться для идентификации этой стратегии при последующем применении. Вторым параметром является тип стратегии, которую вы хотите создать, здесь мы используем username-password или LocalStrategy.

Следует отметить, что по умолчанию LocalStrategy ищет учетные данные пользователя в параметрах username и password, но мы можем также использовать любые другие проименованные параметры.

Переменная конфигурации passReqToCallback позволяет нам получить доступ к объекту request в функции обратного вызова, благодаря чему, в свою очередь, мы имеем возможность использовать любой параметр, связанный с запросом.

Далее, мы используем Mongoose API, чтобы найти пользователя в нашей основной базе пользователей и проверить, является ли он доверенным пользователем или нет.

Последний параметр в нашем обратном вызове done указывает на используемый метод, с помощью которого мы сообщаем модулю Passport об успешном выполнении действия или ошибке.

Чтобы идентифицировать сбой либо первый параметр должен содержать ошибку, либо второй параметр должен содержать значение false. Для обозначения успешного прохождения действия первый параметр должен иметь значение null, а второй – truthy, в этом случае объект request становится доступен.

Поскольку пароли по своей природе являются уязвимым местом, мы всегда должны шифровать их перед сохранением в базу данных. Для этого мы используем bcrypt-nodejs, который помогает шифровать и расшифровывать пароли:

Если вам неудобно работать с отдельными фрагментами кода, и вы предпочитают видеть полный код в действии, вы можете просмотреть его здесь.

Теперь мы определяем следующую стратегию, которая будет обрабатывать регистрацию нового пользователя и создавать его учетную запись в основной базе данных Mongo DB:

passport.use('signup', new LocalStrategy({
    passReqToCallback : true
  },
  function(req, username, password, done) {
    findOrCreateUser = function(){
      // поиск пользователя в Mongo с помощью предоставленного имени пользователя
      User.findOne({'username':username},function(err, user) {
        // В случае любых ошибок - возврат
        if (err){
          console.log('Error in SignUp: ' err);
          return done(err);
        }
        // уже существует
        if (user) {
          console.log('User already exists');
          return done(null, false, 
             req.flash('message','User Already Exists'));
        } else {
          // если пользователя с таки адресом электронной почты
          // в базе не существует, создать пользователя
            var newUser = new User();
          // установка локальных прав доступа пользователя
          newUser.username = username;
          newUser.password = createHash(password);
          newUser.email = req.param('email');
          newUser.firstName = req.param('firstName');
          newUser.lastName = req.param('lastName');

          // сохранения пользователя
          newUser.save(function(err) {
            if (err){
              console.log('Error in Saving user: ' err);  
              throw err;  
            }
            console.log('User Registration succesful');    
            return done(null, newUser);
          });
        }
      });
    };

    // Отложить исполнение findOrCreateUser и выполнить 
    // метод на следующем этапе цикла события
    process.nextTick(findOrCreateUser);
  });
);

Здесь мы снова использовали Mongoose API, чтобы выяснить, существует ли пользователь с данным именем пользователя или нет. Если нет, то создаем нового пользователя и сохраняем информацию о нем в Mongo.

В противном случае возвращаем ошибку с помощью обратного вызова done и флэш-сообщения. Обратите внимание, что мы используем bcrypt-nodejs для создания хэша пароля перед его сохранением:

В общем, схема нашего приложения будет выглядеть так:

Теперь мы задаем маршруты для применения в следующем модуле, который принимает экземпляр паспорта созданного ранее в app.js. Сохраните этот модуль в файле routes/index.js:

module.exports = function(passport){

  /* Получение страницы авторизации. */
  router.get('/', function(req, res) {
    // Вывод страницы авторизации со всеми флэш-сообщениями, если
    // таковые существуют
    res.render('index', { message: req.flash('message') });
  });

  /* Обработка POST-данных авторизации */
  router.post('/login', passport.authenticate('login', {
    successRedirect: '/home',
    failureRedirect: '/',
    failureFlash : true 
  }));

  /* Получение страницы регистрации */
  router.get('/signup', function(req, res){
    res.render('register',{message: req.flash('message')});
  });

  /* Обработка регистрационных POST-данных */
  router.post('/signup', passport.authenticate('signup', {
    successRedirect: '/home',
    failureRedirect: '/signup',
    failureFlash : true 
  }));

  return router;
}

Наиболее важной частью приведенного выше фрагмента кода является использование passport.authenticate() для делегирования аутентификации стратегиям login и signup, когда HTTP POST выполнен для маршрутов /login и /signup соответственно.

Обратите внимание, что не обязательно называть стратегии соответственно пути маршрута, им можно назначать произвольные имена.

Далее, мы создаем следующие два представления для нашего приложения:

extends layout

block content
  div.container
    div.row
      div.col-sm-6.col-md-4.col-md-offset-4
        h1.text-center.login-title Sign in to our Passport app
          div.account-wall
            img(class='profile-img', src='https://lh5.googleusercontent.com/-b0-k99FZlyE/AAAAAAAAAAI/AAAAAAAAAAA/eu7opA4byxI/photo.jpg?sz=120')
            form(class='form-signin', action='/login', method='POST')
              input(type='text', name='username' class='form-control', placeholder='Email',required, autofocus)
              input(type='password', name='password' class='form-control', placeholder='Password', required)
              button(class='btn btn-lg btn-primary btn-block', type='submit') Sign in
              span.clearfix
          a(href='/signup', class='text-center new-account') Create an account
          #message
          if message
            h1.text-center.error-message #{message}

Благодаря Bootstrap наша страница авторизации теперь выглядит следующим образом:

Нам также потребуются еще два представления для ввода регистрационных данных и для домашней страницы приложения:

Если вы не работали с Jade, здесь можете найти документацию по нему.

Passport, будучи связующим софтом, позволяет добавлять определенные свойства и методы к объектам запросов и ответов, что в свою очередь дает возможность добавить очень удобный метод request.logout(), который отменяет сеанс пользователя:

Passport также предоставляет возможность защитить доступ к маршруту, который не предназначен для анонимных пользователей.

Это означает, что если некоторые пользователи пытается получить доступ к маршруту http://localhost:3000/home без авторизации в системе, они будут перенаправлены на главную страницу следующим образом:

Passport не является единственным возможным решением, когда речь заходит об аутентификации приложений Node.js, существуют и альтернативные варианты, такие как EveryAuth.

Но большое количество модулей, гибкость, поддержка сообщества и тот факт, что он является просто связующим программным обеспечением, действительно выделяет Passport из череды других приложений.

Верификация


Подключим и настроим стратегию авторизации.

Вход пользователей в систему

Вот как выглядит схема действий, выполняемых в том случае, когда пользователь пытается войти в систему.

Вход пользователя в систему

Вот что происходит при входе пользователя в систему:

  • Клиент отправляет серверу комбинацию, состоящую из публичного идентификатора и приватного ключа пользователя. Обычно это — адрес электронной почты и пароль.
  • Сервер ищет пользователя в базе данных по адресу электронной почты.
  • Если пользователь существует в базе данных — сервер хэширует отправленный ему пароль и сравнивает то, что получилось, с хэшем пароля, сохранённым в базе данных.
  • Если проверка оказывается успешной — сервер генерирует так называемый токен или маркер аутентификации — JSON Web Token (JWT). 


JWT — это временный ключ. Клиент должен отправлять этот ключ серверу с каждым запросом к аутентифицированной конечной точке.

Генерирование jwt в node.js

Давайте создадим функцию

generateToken

, которая нужна нам для завершения работы над сервисом аутентификации пользователей.

Создавать JWT можно с помощью библиотеки jsonwebtoken. Найти эту библиотеку можно в npm.

Зависимости:

Так же я буду использовать для удобства несколько дополнительных утилит. Без них вполне можно обойтись:

Защита конечных точек и проверка jwt

Теперь клиентскому коду нужно отправлять JWT в каждом запросе к защищённой конечной точке.

Рекомендуется включать JWT в заголовки запросов. Обычно их включают в заголовок Authorization.

Заголовок Authorization

Теперь, на сервере, нужно создать код, представляющий собой промежуточное ПО для маршрутов express. Поместим этот код в файл isAuth.ts:

Использование jwt с express

В этом руководстве мы создадим простое веб-приложение на основе
микросервисов для управления книгами в библиотеке с двумя сервисами.
Одна служба будет отвечать за аутентификацию пользователей, а другая –
за управление книгами.

Будет два типа пользователей – администраторы и участники .
Администраторы смогут просматривать и добавлять новые книги, а участники

  • только просматривать их. В идеале они также могли бы иметь возможность
    редактировать или удалять книги. Но чтобы статья была как можно проще,
    мы не будем вдаваться в подробности.

Для начала в вашем терминале инициализируйте пустой проект Node.js с
настройками по умолчанию:

 $ npm init -y 

Затем давайте установим фреймворк Express:

 $ npm install --save express 

Как имперсонировать пользователя?

Имперсонация пользователей — это техника, используемая для входа в систему под видом некоего конкретного пользователя без знания его пароля.

Эта возможность весьма полезна для супер-администраторов, разработчиков или сотрудников служб поддержки. Имперсонация позволяет им решать проблемы, которые проявляются только в ходе работы пользователей с системой.

Работать с приложением от имени пользователя можно и не зная его пароля. Для этого достаточно сгенерировать JWT с правильной подписью и с необходимыми метаданными, описывающими пользователя.

Создадим конечную точку, которая может генерировать токены для входа в систему под видом конкретных пользователей. Этой конечной точкой сможет пользоваться только супер-администратор системы.

Для чала нам нужно назначить этому пользователю роль, с которой связан более высокий, чем у других пользователей, уровень привилегий. Это можно сделать множеством различных способов. Например, достаточно просто добавить поле role в сведения о пользователе, хранящиеся в базе данных.

Выглядеть это может так, как показано ниже.

Новое поле в сведениях о пользователе

Книжная служба

После этого давайте создадим books.js для нашего книжного сервиса.

Мы начнем с файла, импортировав необходимые библиотеки и настроив
приложение Express:

 const express = require('express'); 
 const bodyParser = require('body-parser'); 
 const jwt = require('jsonwebtoken'); 
 
 const app = express(); 
 
 app.use(bodyParser.json()); 
 
 app.listen(4000, () => { 
 console.log('Books service started on port 4000'); 
 }); 

После настройки, чтобы смоделировать базу данных, давайте просто
создадим массив книг:

 const books = [ 
 { 
 "author": "Chinua Achebe", 
 "country": "Nigeria", 
 "language": "English", 
 "pages": 209, 
 "title": "Things Fall Apart", 
 "year": 1958 
 }, 
 { 
 "author": "Hans Christian Andersen", 
 "country": "Denmark", 
 "language": "Danish", 
 "pages": 784, 
 "title": "Fairy tales", 
 "year": 1836 
 }, 
 { 
 "author": "Dante Alighieri", 
 "country": "Italy", 
 "language": "Italian", 
 "pages": 928, 
 "title": "The Divine Comedy", 
 "year": 1315 
 }, 
 ]; 

Теперь мы можем создать очень простой обработчик запросов для извлечения
всех книг из базы данных:

 app.get('/books', (req, res) => { 
 res.json(books); 
 }); 

Потому что наши книги должны быть видны только авторизованным
пользователям. Нам нужно создать промежуточное ПО для аутентификации.

Перед этим создайте секрет токена доступа для подписи JWT, как и раньше:

 const accessTokenSecret = 'youraccesstokensecret'; 

Этот токен должен быть таким же, как и в службе аутентификации.
Поскольку секреты разделяются между ними, мы можем пройти аутентификацию
с помощью службы аутентификации, а затем авторизовать пользователей в
службе книг.

На этом этапе давайте создадим промежуточное ПО Express, которое
обрабатывает процесс аутентификации:

Модель пользователя

Для начала, я думаю, можно создать модель пользователя:

Подключение passport к express

Окей, с этим разобрались, теперь нужно подключить Passport к Express:

// Middlewares, которые должны быть определены до passport:
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'SECRET' }));
 
// Passport:
app.use(passport.initialize());
app.use(passport.session());

Преимущество использования jwt перед традиционными методами

Как мы обсуждали ранее, JWT может содержать всю информацию о самом
пользователе, в отличие от аутентификации на основе сеанса.

Это очень полезно для масштабирования веб-приложений, например
веб-приложений с микросервисами. Сегодня архитектура современного
веб-приложения выглядит примерно так:

<img src="https://rukovodstvo.net/data:image/svg xml,” loading=”lazy” alt=”web_application_architecture”>

Все эти службы могут быть одной и той же службой, которая будет
перенаправлена балансировщиком нагрузки в соответствии с использованием
ресурсов (ЦП или использование памяти) каждого сервера или некоторыми
различными службами, такими как аутентификация и т. Д.

Если мы используем традиционные методы авторизации, такие как файлы
cookie, нам придется совместно использовать базу данных, такую как
Redis , для обмена сложной информацией между
серверами или внутренними службами. Но если мы поделимся секретом между
микросервисами, мы можем просто использовать JWT, и тогда для
авторизации пользователей не потребуется никаких других внешних
ресурсов.

Привязка авторизации к пользователю

В типичном веб-приложении, учетные данные, используемые для аутентификации пользователя будет передаваться только во время авторизации. Если все в порядке, и пользователь существует, то информация о нем сохраняется в сессию, а идентификатор сессии, в свою очередь, сохраняется в cookies браузера.

Проверка авторизации

Проверку авторизации можно делать с помощью req.isAuthenticated(). Я вынесу проверку в middleware.

exports.mustAuthenticatedMw = function (req, res, next){
  req.isAuthenticated()
    ? next()
    : res.redirect('/');
};

И добавлю в routes.

  App.all('private', mustAuthenticatedMw);
  App.all('private/*', mustAuthenticatedMw);

Регистрация пользователей в системе

Когда в системе создаётся новый пользователь, его пароль необходимо хэшировать и сохранить в базе данных. Пароль в базе сохраняют вместе с адресом электронной почты и другими сведениями о пользователе (например, среди них может быть профиль пользователя, время регистрации и так далее).

Служба аутентификации

Затем давайте создадим файл auth.js , который будет нашей службой
аутентификации:

 const express = require('express'); 
 const app = express(); 
 
 app.listen(3000, () => { 
 console.log('Authentication service started on port 3000'); 
 }); 

В идеале мы должны использовать базу данных для хранения информации о
пользователях. Но для простоты давайте создадим массив пользователей,
который мы будем использовать для их аутентификации.

Создание роутера и контроллеров

Настало время настройки роутера. Привяжем запросы к соответствующим контроллерам:

Структура jwt

Давайте поговорим о структуре JWT на примере токена:

<img src="https://rukovodstvo.net/data:image/svg xml,” loading=”lazy” alt=”sample_json_web_token_jwt”>

Как вы можете видеть на изображении, JWT состоит из трех частей, каждая
из которых разделена точкой.

Боковая панель: кодирование Base64 – это один из способов убедиться, что
данные не повреждены, поскольку оно не сжимает и не шифрует данные, а
просто кодирует их способом, понятным большинству систем. Вы можете
прочитать любой текст в кодировке
Base64 , просто
декодировав его.

Первый раздел JWT – это заголовок, представляющий собой строку в
кодировке Base64. Если вы расшифруете заголовок, он будет выглядеть
примерно так:

 { 
 "alg": "HS256", 
 "typ": "JWT" 
 } 

Раздел заголовка содержит алгоритм хеширования, который использовался
для генерации знака и типа токена.

Второй раздел – это полезная нагрузка, содержащая объект JSON, который
был отправлен обратно пользователю. Поскольку он закодирован только в
Base64, любой может легко его декодировать.

Рекомендуется не включать в JWT какие-либо конфиденциальные данные,
такие как пароли или личную информацию.

Обычно тело JWT выглядит примерно так, хотя это необязательно:

 { 
 "sub": "1234567890", 
 "name": "John Doe", 
 "iat": 1516239022 
 } 

В большинстве случаев sub свойство будет содержать идентификатор
пользователя, а свойство iat , которое является сокращением для
выданного в , является меткой времени, когда был выпущен токен.

Вы также можете увидеть некоторые общие свойства, такие как eat или
exp , который является сроком действия токена.

Последний раздел – это подпись токена. Это создается путем хеширования
строки
base64UrlEncode(header) “.” base64UrlEncode(payload) secret с
использованием алгоритма, упомянутого в разделе заголовка.

secret – это случайная строка, которую должен знать только сервер.
Никакой хеш не может быть преобразован обратно в исходный текст, и даже
небольшое изменение исходной строки приведет к другому хешу. Таким
образом, secret не может быть реконструирован.

Когда эта подпись отправляется обратно на сервер, она может проверить,
что клиент не изменил никаких деталей в объекте.

Структура проекта

Проект имеет следующую структуру:

Теория

Аутентификация и авторизация

Понятия “аутентификация” и “авторизация” часто употребляются как синонимы, но на самом деле они обозначают два разных процесса.

Если кратко, то аутентификация — это проверка того, кем является пользователь, т.е. определение того, что пользователь зарегистрирован в нашей системе, о чем, в частности, может свидетельствовать наличие данных пользователя в нашей базе данных. Авторизация же — это процесс определения полномочий пользователя, т.е. того, к чему пользователь имеет доступ, какие данные нашего приложения он может просматривать, редактировать, удалять и т.д.

В качестве примера сравнения аутентификации и авторизации из реальной жизни можно привести систему безопасности аэропорта. Сначала мы предъявляем паспорт для подтверждения нашей личности (аутентификация, идентификация), затем посадочный талон для подтверждения нашего доступа на самолет (авторизация).

Признаки аутентификации:

Признаки авторизации:

Таким образом, для доступа к приложению требуется как аутентификация, так и авторизация. Если пользователь не может подтвердить свою личность (идентичность, identity), он не будет иметь доступа. И даже если пользователь подтвердил свою личность, но не авторизовался, в доступе ему будет отказано.

Токен

Node.js: шаблон сервера для аутентификации и авторизации / Хабр

Под токеном в рамках настоящей статьи подразумевается JSON Web Token.

JWT — это открытый стандарт (RFC 7519), определяющий компактный и автономный способ безопасной передачи данных между сторонами в виде объекта формата JSON. JWT — это стандарт, т.е. все JWT являются токенами, но не все токены являются JWT.

Требования к проекту


Вот требования к проекту, которым мы будем здесь заниматься:

  • Наличие базы данных, в которой будет храниться адрес электронной почты пользователя и его пароль, либо — clientId и clientSecret, либо — нечто вроде комбинации из приватного и публичного ключей.
  • Использование сильного и эффективного криптографического алгоритма для шифрования пароля.

В тот момент, когда я пишу этот материал, я считаю, что лучшим из существующих криптографических алгоритмов является Argon2. Я прошу вас не использовать простые криптографические алгоритмы вроде SHA256, SHA512 или MD5.

Кроме того, предлагаю вам взглянуть на этот замечательный материал, в котором вы можете найти подробности о выборе алгоритма для хэширования паролей.

Итоги

Нет ничего плохого в том, чтобы полагаться на сторонние сервисы и библиотеки аутентификации. Это помогает разработчикам экономить время. Но им необходимо ещё и знать о том, на каких принципах основана работа систем аутентификации, о том, что обеспечивают функционирование таких систем.

В этом материале мы исследовали возможности JWT-аутентификации, поговорили о важности выбора хорошего криптографического алгоритма для хэширования паролей. Мы рассмотрели создание механизма имперсонации пользователей.

Сделать то же самое с помощью чего-то вроде passport.js далеко не так просто. Аутентификация — это огромная тема. Возможно, мы к ней ещё вернёмся.

Уважаемые читатели! Как вы создаёте системы аутентификации для своих Node.js-проектов?

Заключение

В этой статье мы познакомили вас с JWT и как реализовать JWT с Express.
Я надеюсь, что теперь у вас есть хорошие знания о том, как работает JWT
и как реализовать его в своем проекте.

Как всегда, исходный код доступен на
GitHub .

Похожее:  Авито (Avito ru) личный кабинет - вход в мои объявления по номеру телефона, подать обяявление бесплатно, регистрация

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *