Обработка аутентификации в NextJS на Payload CMS

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

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

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

Обзор

Для этой статьи создано два репозитория кода, которые будут использоваться в качестве справочника.

  1. payloadcms/next-auth-frontend — React-приложение, построенное на NextJS. Это начальный сайт, который включает маршруты входа и выхода, а также формы для входа, забытого пароля и сброса пароля. Оно также демонстрирует, как фронтенд будет вызывать бэкенд для аутентифицированного пользователя.
  2. payloadcms/next-auth-cms — приложение Payload CMS, настроенное для работы с базой данных, хранения учетных данных пользователей и API для обработки запросов REST или GraphQL, на которых построен наш пример аутентификации.

Вы можете следовать разделам по началу работы с каждым из предоставленных репозиториев. Установка каждого из них займет всего несколько минут. Функции посева вызываются из функции onInit, найденной в payload.config.ts нашего приложения next-auth-cms. При запуске сервера у вас уже должен быть пользователь admin и клиент, как определено для каждой роли, а также домашняя страница.

Аутентификация пользователя

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

Мы еще не вошли в систему, и пользовательский интерфейс отражает это.

Если бы мы посмотрели на инструменты проверки браузера, показывающие сетевой трафик, и обновили страницу, мы бы увидели, что на backend выполняется вызов, который определяет состояние пользователя. Маршрут представляет собой GET-запрос к /api/users/me на бэкенде, который на данный момент просто возвращает user: null.

Этот вызов был определен как useEffect, встроенный в компонент Auth Provider в auth-next-frontend в /components/Auth/index.ts. Полезно понимать, что пользователь в этом контексте auth в любой момент времени может находиться в одном из трех состояний: undefined, до завершения запроса, null как гость, или успешно возвращенный объект пользователя.

useEffect(() => {
  const fetchMe = async () => {
    const result = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/me`, {
      // Make sure to include cookies with fetch
      credentials: 'include',
    })
      .then((req) => req.json());
    setUser(result.user || null);
  };
  fetchMe();
}, []);
Вход в полноэкранный режим Выход из полноэкранного режима

Получение правильного пользователя обратно из запроса API возможно благодаря http cookie, включенному в запрос fetch, который Payload API автоматически создан и готов обработать для нас.

Вход в систему

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

На скриншоте мы видим базовую форму, которая выполняет работу по отправке введенных учетных данных провайдеру авторизации путем
вызывая login из useAuth.

Форма входа находится в /pages/login/index.ts из auth-next-frontend и обрабатывает основные сообщения об ошибках, но в остальном оставлена максимально простой.
в остальном он оставлен настолько простым, насколько это возможно.

Управление учетными записями и контроль доступа

Предполагая, что мы успешно ввели учетные данные пользователя, мы должны оказаться на странице /account. Эта форма используется для отправки обновлений коллекции пользователя, вошедшего в систему. Здесь не требуется никакой работы с API, поскольку Payload уже позаботился об этом за нас, и это можно сделать с помощью GraphQL или REST, как мы сделали здесь.

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

Проверяем теперь код бэкенда, коллекция пользователей в next-auth-cms имеет access, определенный таким образом, что Боб или администратор могут читать только его.
только Боб или администратор могут читать или обновлять пользователя.

Выход из системы

Функциональность выхода из системы очень похожа на вход, за исключением того, что мы устанавливаем пользователя в состоянии frontend в null по завершении. Бэкэнд API больше не будет принимать запросы от cookie аутентификации, который был возвращен при входе в систему.

Создание учетной записи

Теперь, когда мы больше не аутентифицированы как bob. Мы можем создать новую учетную запись. Вот код, который обрабатывает отправку формы create-account.

const onSubmit = useCallback(async (data: FormData) => {
  const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users`, {
    method: 'POST',
    body: JSON.stringify(data),
    headers: {
      'Content-Type': 'application/json',
    },
  })

  if (response.ok) {
    // Automatically log the user in
    await login({
      email: data.email,
      password: data.password
    });

    // Set success message for user
    setSuccess(true);

    // Clear any existing errors
    setError('')
  } else {
    setError('There was a problem creating your account. Please try again later.');
  }
}, []);
Вход в полноэкранный режим Выход из полноэкранного режима

На высоком уровне мы отправляем данные формы в конечную точку POST /api/users с последующим входом в систему с теми же учетными данными.

Это возможно из-за нашего контроля доступа к пользователям. Вы могли заметить, что доступ для create установлен на return true.
Это позволяет гостевому пользователю создать новую учетную запись клиента. Если бы это значение не было установлено, Payload использовал бы управление доступом по умолчанию, которое разрешает запросы для любого вошедшего в систему пользователя. Это, конечно, не работает для анонимных пользователей.

Вы можете спросить, что мешает пользователю создать учетную запись с ролью admin?

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

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

Восстановление пароля

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

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

Безопасность

Разделяя бэкенд и фронтенд, мы также должны иметь правильно настроенный Cross Origin Resource Sharing (CORS). Без этого мы не сможем делать вызовы API с фронтенда с другого веб-адреса. Payload имеет простую конфигурацию для CORS, и вы можете видеть, что она уже настроена в файле payload.config.ts в next-auth-cms с помощью переменных окружения, определенных в .env. Вам не нужно настраивать CORS, если ваши запросы осуществляются из одного домена.

Использование http-only cookies является принципиальной деталью в работе современной архитектуры REST. Это важный инструмент для построения безопасных и масштабируемых приложений. Надеюсь, это руководство помогло вам понять и реализовать его для вашей следующей большой идеи.

Подведение итогов

Вот и все! Мы полностью заблокировали наше приложение и предоставили доступ только нужным людям.

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

Найдите нас в twitter @payloadcms, если вам понравилась эта статья, или присоединяйтесь к нашему растущему сообществу Discord.

Оцените статью
devanswers.ru
Добавить комментарий