Мы объединили две независимые системы (Drupal и Sails.js) для совместной работы, и это сэкономило нам время на разработку интерфейса за счет использования уже настроенной и настраиваемой CMS (Drupal). Поскольку нам пришлось использовать некоторую бизнес-логику, включая вычисления в реальном времени, push-уведомления и легко потребляемый API для мобильных приложений, фреймворк Sails.js дал нам прочную основу.

Что хотел клиент…

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

Что мы сделали…

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

Проблема заключалась в том, что нам нужно было использовать учетные записи пользователей из Drupal, но сохранение экземпляра библиотеки Waterwheel в каждом пользовательском сеансе невозможно из-за того, что Redis отключил от него функции и интерфейсы. Следующая проблема заключалась в том, что Waterwheel запускает процесс аутентификации OAuth каждый раз, когда в конфигурации присутствует экземпляр с полями имени пользователя и пароля. Недопустимо, чтобы пользователь ждал минимум 3 секунды для каждого запроса. Но в исходном коде Waterwheel мы обнаружили, что процесс OAuth не запустится снова, если присутствует объект tokenInformation с действующим токеном. Мы разделили библиотеку, сделали несколько оптимизаций, а также реализовали поддержку запросов PATCH с JSONAPI. Он доступен на нашем GitHub.

Как прошел процесс внедрения?

Каждый узел Drupal имеет свой собственный файл службы Sails.js, который отправляет запросы в Drupal. Сервисы вызываются из контроллеров.

Чтобы правильно соединить Drupal с Sails.js, мы создали экземпляр Waterwheel instance в функции login (req, res) в UserController и вызвали services / User.getCurrentUser с этим экземпляром. В результате того, что библиотека Waterwheel создала OAuth, к экземпляру был добавлен объект tokenInformation. Затем мы выбрали только этот объект и сохранили его в сеансе пользователя.

Чтобы использовать сохраненный объект tokenInformation в следующих запросах, нам нужно было создать политику «водяное колесо» и разрешить ее для всех запросов кроме входа в policy.js config. Сохраненный объект tokenInformation извлекается из сеанса и добавляется к объекту req, к которому позже можно будет получить доступ как «req.waterwheel» - это экземпляр Waterwheel пользователя .

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

Пришлось решить проблемы с OAuth 2.0

Мы также столкнулись с проблемами с процессом аутентификации OAuth, потому что, как сказано в спецификации OAuth 2.0: «обновленный токен доступа может иметь исходные области действия или меньше».

Поскольку наши мобильные приложения предназначены для использования преподавателями и учащимися, у нас есть несколько ролей, отправляемых в конфигурации Waterwheel с каждым запросом («роли» = «области» в OAuth). Drupal управляет ситуацией, поскольку он назначает только те роли, которые действительны для пользователя, который в данный момент пытается пройти аутентификацию.

Пример: библиотека Waterwheel отправляет запрос с 3 запрошенными областями («студент», «учитель», «аутентифицирован»), но ученику не разрешено быть «учителем», чтобы процесс аутентификации пропускал одну недопустимую роль и присваивал только две допустимые роли токену пользователя.

Проблема начинается, когда мы пытаемся обновить просроченный токен доступа с обновленным токеном и всеми областями. Если одна область недействительна, сервер OAuth 2.0 сгенерирует исключение. По этой причине мы разделили серверную библиотеку OAuth 2.0 и изменили ее поведение, чтобы она автоматически пропускала недопустимые роли, не вызывая исключения. Наряду с этим мы оптимизировали его установку (включая поставщика) и добавили допустимые области в ответ при получении нового токена, потому что нам нужно было знать допустимые области действия пользователя в коде Sails.js и потому, что Drupal не возвращает роли пользователя при выполнении запроса. с JSONAPI нам нужно было получать роли из другого источника. Разветвленная библиотека доступна на нашем GitHub.

Конец истории…

Создав коннектор Drupal-Sails.js, мы подготовили полностью рабочий шаблон для наших будущих проектов на тот случай, если нам понадобится управление контентом с настраиваемым пользовательским интерфейсом и отдельный сервер- сторона бизнес-логики. Несмотря на то, что мы разделили 2 библиотеки и немного изменили их, мы не нарушили спецификации какого-либо стандарта (например, OAuth) и можем обновить их из исходных основных ветвей.