Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Angular
Code

Аутентификация на основе токена с помощью AngularJS & NodeJS

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Marat Amerov (you can also view the original English article)

Final product image
What You'll Be Creating

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

Традиционные системы аутентификации

Прежде чем приступить к аутентификации на основе токенов, давайте сначала рассмотрим традиционную систему аутентификации.

  1. Пользователь вводит имя пользователя и пароль в форме входа в систему и нажимает кнопку «Вход».
  2. После того, как запрос отправлен, проверяется пользователь на бэкэнде, путем запроса в базу данных. Если запрос действителен, создается сессия, используя информацию пользователя, полученную из базы данных, а затем возвращается информация о сессии в заголовок ответа, чтобы сохранить идентификатор сессии в браузере.
  3. Необходимо предоставить информацию о сессии для доступа к ограниченным точкам входа в приложение.
  4. Если информация сессии валидна, предоставим пользователю доступ к указанным точкам входа и отдадим HTML-контент.

Все хорошо до этого момента. Веб-приложение работает хорошо, и оно может аутентифицировать пользователей, чтобы они могли получить доступ к ограниченным точкам входа; Однако, что происходит, если вы хотите разработать другой клиент, скажем для Android, для вашего приложения? Сможете ли вы использовать текущее приложение для аутентификации мобильных клиентов и для работы с ограниченным контентом? В данный момент - нет. Для этого есть две основные причины:

  1. Сессии и файлы cookie не имеют смысла для мобильных приложений. Вы не можете обмениваться сессиями или файлами cookie, созданными на стороне сервера, с мобильными клиентами.
  2. В текущем приложении, возвращается отрендеренный HTML. В мобильном клиенте вам нужно что-то вроде JSON или XML в качестве ответа.

В этом случае вам необходимо клиентское приложение.

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

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

Он будет использовать следующий поток управления:

  1. Пользователь вводит имя пользователя и пароль в форме входа в систему и нажимает кнопку «Вход».
  2. После того, как запрос отправлен, происходит проверка пользователя на сервере, выполнив запрос к базе данных. Если запрос валидный, создается токен, используя информацию пользователя, полученную из базы данных, и затем возвращается эта информация в заголовок ответа, чтобы мы могли хранить браузере токен в локальном хранилище.
  3. Предоставляется токен с информацией в каждом заголовке запроса для доступа к ограниченным точкам входа в приложение.
  4. Если токен полученный из заголовка запроса, является допустимым, предоставляется доступ пользователю к указанной точке входа и ответ в JSON или XML.

В этом случае у нас нет возвращенной сессии или файла cookie, и мы не возвращаем никакого HTML-содержимого. Это означает, что мы можем использовать эту архитектуру для любого клиента приложения. Вы можете увидеть схему архитектуры ниже:

Итак, что это за JWT?

JWT

JWT означает JSON Web Token и представляет собой формат токена, используемый в заголовках авторизации. Этот токен помогает безопасно организовать связь между двумя системами. Давайте перефразируем JWT как «токен-носитель» для целей данного руководства. Токен-носитель состоит из трех частей: заголовок, полезная нагрузка и подпись.

  • Заголовок является частью токена, который содержит тип токена и метод шифрования, который также зашифровывается с base-64.
  • Полезная нагрузка включает в себя информацию. Вы можете помещать любые данные, такие как информация пользователя, информация о продукте и т. д. Все они хранится с использованием шифрования base-64.
  • Подпись состоит из комбинаций заголовка, полезной нагрузки и секретного ключа. Секретный ключ должен быть безопасно сохранен на стороне сервера.

Вы можете увидеть схему JWT и примерный токен ниже;

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

Языки и URL библиотек
NodeJS http://github.com/auth0/node-jsonwebtoken
PHP http://github.com/firebase/php-jwt
Java http://github.com/auth0/java-jwt
Ruby http://github.com/progrium/ruby-jwt
.NET http://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet
Python http://github.com/progrium/pyjwt/

Практический пример

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

  1. Запросы выполняются несколькими клиентами, такими как веб-приложение, мобильный клиент и т. д., в API для определенной цели.
  2. Запросы отправляются на сервис, например https://api.yourexampleapp.com. Если приложение используют много пользователей, для обслуживания запрошенной операции может потребоваться несколько серверов.
  3. Здесь балансировщик нагрузки используется для балансировки запросов, чтобы наилучшим образом использовать серверы приложений на бекенде. Когда вы выполняете запрос на https://api.yourexampleapp.com, сначала балансировщик нагрузки обрабатывает запрос, а затем перенаправляет клиент на определенный сервер.
  4. Существует одно приложение, и это приложение развертывается на нескольких серверах (сервер-1, сервер-2, ..., сервер-n). Всякий раз, когда делается запрос на https://api.yourexampleapp.com, бекенд приложение перехватывает заголовок запроса и извлекает информацию о токенах из заголовка авторизации. Запрос к базе данных будет выполнен с использованием этого токена. Если этот токен действителен и имеет необходимое разрешение для доступа к запрашиваемой точке входа, запрос будет продолжен. Если нет, он вернет код ответа 403 (что указывает на запрещенный статус).

Преимущества

Аутентификация на основе токенов имеет ряд преимуществ, которые решают серьезные проблемы. Некоторые из них:

  • Клиенты независимые от сервиса. При аутентификации на токенах, токен передается через заголовки запросов, вместо того, чтобы хранить информацию аутентификации в сессиях или куки. Это означает, что нет стейта. Вы можете отправить запрос на сервер с любого типа клиента, который может выполнять HTTP-запросы.
  • CDN. В большинстве современных веб-приложений виды рендерятся на бекенде и HTML-содержимое возвращается в браузер. Логика интерфейса зависит от бекенд кода. Нет необходимости делать такую ​​зависимость. Это связано с несколькими проблемами. Например, если вы работаете с дизайнерским агентством, которое реализует ваши интерфейсные HTML, CSS и JavaScript, вам нужно взять этот внешний интерфейс и перенести его в свой внутренний код, чтобы сделать некоторый рендеринг или выполнении операции. Через некоторое время ваш отображаемый HTML-контент будет сильно отличаться от того, что внедрено агентством. При аутентификации на основе токенов вы можете разрабатывать фронтенд проект отдельно от бекенд кода. Ваш бекенд код вернет ответ в JSON вместо рендеринга HTML, и вы можете поместить мини-версию gzipped-кода в CDN. Когда вы перейдете на свою веб-страницу, HTML-содержимое будет передано из CDN, а содержимое страницы будет заполнено сервисами API с использованием токена в заголовках авторизации
  • No Cookie-Session (or No CSRF). CSRF является серьезной проблемой в современной веб-безопасности, поскольку он не проверяет, является ли источник запроса доверенным или нет. Чтобы решить эту проблему, пул токенов используется для отправки этого токена на каждый пост-запрос формы. В аутентификации на основе токенов используется в заголовках авторизации, а CSRF не включает эту информацию.
  • Постоянное хранилище токенов. Когда в приложении выполняется сеанс чтения, записи или удаления, операция c  файлами будет выполняться в папке temp операционной системы, по крайней мере, в первый раз. Предположим, что у вас несколько серверов, и сессия создается на первом сервере. Когда вы делаете другой запрос и ваш запрос падает на другой сервер, информация о сессии не будет существовать и получит «неавторизованный» ответ. Я знаю, вы можете решить это с помощью привязанной сессии. Однако при аутентификации на основе токенов этот случай решается естественным образом. Нет проблемы с привязкой сессией, потому что токен запроса перехватывается при каждом запросе на любом сервере.

Это наиболее распространенные преимущества аутентификации и обмена данными на токенах. Это конец теоретических и архитектурных разговоров о аутентификации на токенах. Пришло время для практического примера.

Пример приложения

Вы увидите два приложения для демонстрации аутентификации на токенах:

  1. бэкенд на основе токенов-аутентификации
  2. фронтенд на основе токенов-аутентификации

В бекенд проекте будут реализованы сервисы, а результаты будут в формате JSON. В службы не возвращают представления. В фронтенд проекте будет проект AngularJS для интерфейса, а затем в фронтенд приложение будут добавленны службы AngularJS для выполнения запросов к бекенд службам.

бэкенд на основе токенов-аутентификации

В базовом проекте есть три основных файла:

  • package.json предназначен для управления зависимостями.
  • models\User.js содержит модель User, которая будет использоваться для создания операций с базами данных связанных с пользователями.
  • server.js предназначен для начальной загрузки проекта и обработки запросов.

Это все! Этот проект очень прост, так что вы можете легко понять основную концепцию без глубокого погружения.

package.json содержит зависимости для проекта: express для MVC, body-parser для парсинга параметров форм  в NodeJS, morgan для ведения логирования запросов, mongoose для нашей платформы ORM для подключения к MongoDB и jsonwebtoken для создания токенов JWT с использованием нашей модели пользователя. Существует также атрибут, называемый engines, который сообщает, что этот проект выполняется с использованием версии NodeJS> = 0.10.0. Это полезно для Это полезно для Это полезно для PaaS-сервисов, таких как Heroku. Мы также рассмотрим эту тему в другом разделе.

Мы сказали, что будем генерировать токен, используя полезную нагрузку модели пользователя. Эта модель помогает нам создавать пользовательские операции с MongoDB. В User.js определена пользовательская схема, а модель пользователя создается с использованием модели mongoose. Эта модель готова к работе с базой данных.

Определены наши зависимости, и наша пользовательская модель, поэтому теперь давайте объединим все это для создания сервиса для обработки определенных запросов.

В NodeJS вы можете включить модуль в свой проект, используя require. Во-первых, нам нужно импортировать необходимые модули в проект:

Наш сервис будет обслуживаться через определенный порт. Если какая-либо переменная порта определена в переменных системной среды, вы можете использовать это, мы определили порт 3001. После этого включается модель User, и устанавливается соединение с базой данных для выполнения некоторых пользовательских операций. Не забудьте указать переменную окружения MONGO_URL для URL-адреса подключения к базе данных.

В приведенном выше разделе мы сделали несколько конфигураций для моделирования обработки HTTP-запросов в NodeJS с помощью Express. Мы разрешаем запросы из разных доменов, чтобы разработать независимую от клиента систему. Если вы этого не разрешите, вы вызовете CORS-ошибку (Cross Origin Request Sharing) в веб-браузере.

  • Access-Control-Allow-Origin разрешен для всех доменов.
  • Вы можете отправить POST и GET запросы на этот сервис.
  • Разрешены заголовки X-Requested-With и content-type.

Мы импортировали все необходимые модули и определили нашу конфигурацию, поэтому теперь пришло время определить обработчики запросов. В приведенном выше коде всякий раз, когда вы отправляете POST-запрос /authenticate с именем пользователя и паролем, вы получаете JWT-токен. Во-первых, запрос к базе данных обрабатывается с использованием имени пользователя и пароля. Если пользователь существует, пользовательские данные будут возвращены с помощью токена. Но, что, если нет такого пользователя, который соответствует имени пользователя и / или паролю?

Когда вы выполняете POST-запрос  /signin с именем пользователя и паролем, новый пользователь будет создан с использованием информации из параметров пользователя. На 19-й строке вы можете увидеть, что новый JSON-токен  генерируется с помощью модуля jsonwebtoken, который был назначен переменной jwt. Часть аутентификации готова. Что делать, если мы попытаемся получить доступ к ограниченной точке входа? Как мы можем получить доступ к этой точке входа?

Когда вы делаете GET-запрос  в /me, вы получите текущую информацию о пользователе, но для продолжения работы с запрошенной точкой входа будет выполняться функция ensureAuthorized.

В этой функции заголовки запросов перехватываются, и извлекается заголовок authorization. Если в этом заголовке существует токен-носитель, этот токен назначается req.token для использования во всем запросе, и запрос может быть продолжен с помощью next(). Если токен не существует, вы получите ответ со статусом 403 (Forbidden). Вернемся к обработчику /me и воспользуемся req.token для получения пользовательских данных с помощью этого токена. Всякий раз, когда вы создаете нового пользователя, токен генерируется и сохраняется в пользовательской модели в БД. Эти токены уникальны.

У нас есть только три обработчика для этого простого проекта. После этого вы увидите;

NodeJS-приложение может падать при возникновении ошибки. С приведенным выше кодом это падение предотвращается, и в консоли выводится журнал ошибок. И, наконец, мы можем запустить сервер, используя следующий фрагмент кода.

Подведем итоги:

  • Импортируются модули.
  • Выполнены конфигурации.
  • Определены обработчики запросов.
  • определены middleware для перехвата ограниченных точек входа.
  • Запущен сервер.

Мы закончили работу над бекенд сервисом. Чтобы его можно было использовать несколькими клиентами, вы можете развернуть это простое серверное приложение на своих серверах, или, может быть, можно развернуть его в Heroku. В корневой папке проекта есть файл Procfile. Давайте развернем наш сервис на Heroku.

Развертывание на Heroku

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

Я не буду обсуждать, как создать приложение в Heroku; Вы можете обратиться к этой статье для создания приложения Heroku, если вы этого еще не делали ранее. После создания своего Heroku-приложения вы можете добавить место назначения в свой текущий проект, используя следующую команду:

Теперь вы клонировали проект и добавили место назначения. После git add и git commit вы можете отправить свой код на Heroku, выполнив git push heroku master. Когда вы успешно запушите проект, Heroku выполнит команду npm install для загрузки зависимостей в папку temp на Heroku. После этого он запустит ваше приложение, и вы сможете получить доступ к своему сервису с помощью протокола HTTP.

фтонтенд на основе токенов-аутентификации

Во фронтенд проекте вы увидите проект AngularJS. Здесь я остановлюсь только на основных разделах в проекте, потому что AngularJS не является чем-то, что можно охватить в рамках одного урока.

Вы можете клонировать проект из этого репозитория на GitHub. В этом проекте вы увидите следующую структуру папок:

Folder Structure

ngStorage.js - это библиотека для AngularJS для управления локальными операциями хранения. Кроме того, есть основной лэйаут index.html и партиалы, которые расширяют основной макет в папке partials. controllers.js предназначен для определения действий нашего контроллера в интерфейсе. services.js предназначен для выполнения запросов на наши сервисы, о которых я упомянул в предыдущем проекте. У нас есть файл инициализации приложения, называемый app.js, и в этом файле применяются конфигурации и импорт модулей. Наконец, client.js предназначен для обслуживания статических HTML-файлов (или просто index.html, в данном случае); Это помогает нам обслуживать статические HTML-файлы  при развертывании на сервере без использования Apache или любых других веб-серверов.

В основном HTML-файле макета все необходимые JavaScript-файлы включены для связанных с AngularJS библиотек, а также нашего пользовательского контроллера, сервиса и файла приложения.

В приведенном выше коде определен контроллер HomeCtrl, и внедрены некоторые требуемые модули, как $rootScope и $scope. Инъекция зависимостей является одной из самых мощных возможностей AngularJS. $scope - это переменная-мост между контроллерами и представлениями в AngularJS, что означает, что вы можете использовать test в видах, если вы определили его в указанном контроллере, например $scope.test = ....

В этом контроллере определены некоторые полезные функции, такие как:

  • signin для установки кнопки входа в форму входа
  • signup для обработки формы регистрации
  • me для назначения кнопки Me в лэйауте

В главном лэйауте в главном меню вы можете увидеть атрибут data-ng-controller со значением HomeCtrl. Это означает, что этот dom-элемент меню может совместно использовать скоуп с HomeCtrl. Когда в форме вы нажимаете кнопку регистрации, будет выполнена функция регистрации в файле контроллера, и в этой функции будет использоваться сервис регистрации сервиса Main, который уже внедрен в этот контроллер.

Основной структурой является view -> controller -> service. Эта служба делает простые Ajax-запросы к бекенду, чтобы получить конкретные данные.

В приведенном выше коде вы можете видеть сервисные функции, такие как запросы на аутентификацию. Из controller.js вы, возможно, уже поняли, что существуют такие функции, как Main.me. Сервис Main был внедрен в контроллер, и в контроллере сервисы вызываются напрямую.

Эти функции - это просто Ajax-запросы к нашему сервису, которые мы развернули вместе. Не забудьте указать URL-адрес сервиса в baseUrl в приведенном выше коде. При развертывании сервиса на Heroku вы получите URL-адрес сервиса, такой как appname.herokuapp.com. В приведенном выше коде вы будете устанавливать var baseUrl = "appname.herokuapp.com".

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

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

Во фронтенд части у нас есть некоторые партиал-страницы, такие как signin, signupprofile details и vb. Эти партиал-страницы связаны с конкретными контроллерами. Вы можете видеть это отношение в app.js:

Как вы можете легко понять из приведенного выше кода, что когда вы перейдете на страницу /, будет отображена страница home.html. Другой пример: если вы перейдете в /signup, будет отображаться signup.html. Эта операция рендеринга будет выполняться в браузере, а не на стороне сервера.

Заключение

Вы можете видеть, как все, что мы обсуждали в этом уроке, работает на практике, попробовав это демо.

Системы аутентификации на основе токенов помогают вам создавать систему аутентификации/авторизации при разработке клиент-независимых служб. Используя эту технологию, вы просто сосредоточитесь на своих сервисах (или API).

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

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.