Глубокое погружение в Strapi для создания системы запросов функций EOS в GSOC’20

Hola a todos! Дайте мне компанию, пока я объясню вам внутренности Strapi и то, как я использую различные механизмы для реализации индивидуальных и безопасных решений для нашей системы запросов функций. Возьмите свой напиток, сядьте поудобнее и расслабьтесь, пока я расскажу вам о деталях.

Что я делал на этой неделе?

Strapi - это волшебство, лежащее в основе наших замечательных приложений в EOS. Это ведущая CMS с открытым исходным кодом. Это 100% Javascript, полностью настраиваемый и ориентированный на разработчиков.

На этой неделе я завершил аутентификацию пользователя и авторизацию в нашей системе. Сюда входят функции регистрации, входа, выхода, забытого пароля и сброса пароля. Давайте посмотрим, как это сделать с помощью Strapi и React.

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

Я использовал плагин Roles and Permissions для выполнения своих задач недели. Этот плагин обеспечивает способ защиты нашего API с помощью полного процесса аутентификации на основе JWT. Каждый раз при отправке запроса API сервер проверяет наличие заголовка Authorization и проверяет, имеет ли пользователь, отправляющий запрос, доступ к ресурсу. Для этого наш JWT содержит наш идентификатор пользователя, и мы можем сопоставить группу, в которой находится наш пользователь, и в конце узнать, разрешает ли группа доступ к маршруту.

Ответ API на маршрут аутентификации содержит JWT пользователя в jwt ключе. Нам нужно будет сохранить это JWT в нашем приложении, это важно, потому что вам придется использовать его при следующих запросах.

Мы решили сохранить JWT в httpOnly cookie вместо простого решения - хранить его в localStorage, что делает наше приложение уязвимым для XSS-атак. Это означает, что нам нужно настроить Strapi для установки jwt в cookie вместо того, чтобы возвращать его в ответе API. Это гарантирует, что нашему клиентскому приложению не нужно хранить конфиденциальные данные для будущих аутентифицированных запросов.

Strapi внутренне использует Koa.js, новую веб-платформу, разработанную командой Express, которая стремится стать более компактной, более выразительной и надежной основой для веб-приложений и API. Я быстро изучил базовый синтаксис, так как уже знаком с Node.js и Express.

Теперь каждый плагин в Strapi следует архитектуре, приведенной ниже, и все установленные плагины можно найти в папке node_modules с соглашением об именах strapi-plugin-*.

plugin/
└─── admin/ # Contains the plugin's front-end
|     └─── src/ # Source code directory
|          └─── index.js # Entry point of the plugin
|          └─── pluginId.js # Name of the plugin
|          └─── lifecycles.js # File in which the plugin sets the                     |                              hooks to be ran in another plugin.
|          └─── components/ # Contains the list of React components  |                             used by the plugin
|          └─── containers/
|            └─── App/ # Container used by every others containers
|            └─── Initializer/ # This container is required, it is  |         used to executed logic right after the plugin is mounted.
|            └─── translations/ # Contains the translations to make |                                      the plugin internationalized
|               └─── en.json
|               └─── index.js # File that exports all the plugin's translations.
|               └─── fr.json
└─── config/ # Contains the configurations of the plugin
|     └─── functions/
|        └─── bootstrap.js # Asynchronous bootstrap function that 
|                                runs before the app gets started
|     └─── policies/ # Folder containing the plugin's policies
|     └─── queries/ # Folder containing the plugin's models queries
|     └─── routes.json # Contains the plugin's API routes
└─── controllers/ # Contains the plugin's API controllers
└─── middlewares/ # Contains the plugin's middlewares
└─── models/ # Contains the plugin's API models
└─── services/ # Contains the plugin's API services

Чтобы настроить эти установленные плагины, мы можем работать в каталоге /extensions. Он содержит все настраиваемые файлы плагинов. Я настроил плагин user-permissions, изменив файл контроллера Auth.js для выдачи JWT пользователю и установив его в httpOnly cookie после того, как будут выполнены все проверки на стороне сервера. Я также изменил ответ контроллера, чтобы он возвращал «статусный» ключ со значением «Authenticated» вместо токена. Это подтверждает, что пользователь прошел аутентификацию.

Ждать! Strapi считывает токен из заголовка Authorization в запросе API, поэтому пока это не сработает. Далее я добавил файл permissions.js в папку policies, где я прикрепляю токен к заголовку после прочтения его из файла cookie, который был установлен ранее.

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

Теперь, чтобы реализовать функцию выхода из системы, я настроил пользовательский маршрут /logout с контроллером, чтобы установить для токена значение null в файле cookie. Это безопасно уничтожает сеанс пользователя за секунды.

Ребята, терпения! Наш пользователь тоже может забыть свой пароль. Я использовал службу sendgrid для отправки пользователям электронной почты со ссылкой, которая содержит параметр URL code, который требуется для сброса пароля пользователя.

Я реализовал функциональность на стороне клиента, включая запросы к API, в настраиваемом хуке React с именем useAuth, чтобы наконец завершить гибкую задачу.

Что будет дальше?

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

Я также попытаюсь настроить поставщиков, которые в настоящее время не работают из-за проблемы в Strapi v3.0.1 здесь.

Я где-нибудь застрял?

Мы все обязательно упадем. Все великие дела не начинаются безупречно. Сначала я не мог понять, как правильно управлять состоянием пользователя, и попытался использовать reducer, но при обновлении страницы состояние сбрасывалось до исходного. Наконец, я реализовал идею чтения состояния из localStorage без сохранения какой-либо конфиденциальной информации.

Strapi по умолчанию использует службу sendmail для отправки писем пользователям, но она не работала и всегда возвращала код состояния 400. Я добавил службу sendgrid, чтобы решить эту проблему.

Вся эта суета и суета ознаменовали конец моей недели завораживающим кольцевым солнечным затмением 21 июня 2020 года. Следите за обновлениями, поскольку в ближайшие недели мы представим некоторые удивительные особенности.