Создание потока аутентификации с помощью AWS Cognito

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

Большинство приложений имеют простую функцию регистрации/входа, которую мы будем создавать в этой части серии. Существует множество вариантов использования службы аутентификации: от продуктов Identity-as-a-Service (IaaS), таких как Auth0, Firebase, Okta, AWS Cognito, до создания собственной система управления идентификацией. В этом примере мы будем использовать AWS Cognito.

Обзор

У нас будет два экрана, которые видит неавторизованный пользователь: экран Signup и экран Login. Давайте объединим эти два экрана вместе в макет, который мы назовем Unauthenticated. Макет Authenticated будет отображаться только в том случае, если пользователь правильно прошел аутентификацию в Cognito, и он покажет список элементов, мы создали в части 3. Мы просто добавим кнопку Logout, которая очистит аутентифицированный сеанс пользователя и вернет нас к макету Unauthenticated. Довольно просто, правда? Давай сделаем это.

Немного предыстории

Прежде чем продолжить, я предполагаю, что вы ознакомились с главами Создание пула пользователей Cognito и Создание пула удостоверений Cognito из отличного Учебника по бессерверному стеку. Вы спросите, в чем разница между пулом пользователей и пулом удостоверений? Обязательно прочтите объяснение здесь.

Когда вы закончите настройку пула пользователей и пула удостоверений, давайте сохраним следующие параметры конфигурации в файле конфигурации:

Да, и прежде чем мы продолжим, убедитесь, что вы установили библиотеку AWS Amplify. Это значительно упрощает взаимодействие с Cognito (и другими сервисами AWS):

Настройка маршрутизации

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

Здесь следует отметить одну новую вещь: метод createSwitchNavigator используется для обеспечения того, чтобы мы показывали только один экран/макет за раз. Это именно то, что мы хотим гарантировать, что мы показываем только аутентифицированные экраны, когда пользователь вошел в систему. react-navigation Документация по этому поводу содержит более подробную информацию. Кроме этого, все остальное должно быть знакомо по тому, что мы делали еще в части №2.

Войти с помощью AWS Cognito

Давайте реализуем экран Login, включая вызов сервиса AWS Cognito для аутентификации. Вот как выглядит код этого экрана:

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

Но есть небольшая проблема: мы не видим макет Authenticated после успешного входа в систему. Помните, что SwitchNavigator использует флаг isAuthenticated, чтобы выбрать, отображать ли макет Authenticated или Unauthenticated. Да, мы могли бы обмануть и перейти непосредственно к раскладке Authenticated после успешного входа в систему, но эта специальная навигация может очень быстро стать беспорядочной. Что нам действительно нужно, так это контейнер приложения верхнего уровня для управления этой функциональностью с использованием внутреннего состояния. И мы также хотим, чтобы дочерние элементы контейнера приложения изменяли это состояние (с обратным вызовом) всякий раз, когда изменяется состояние аутентификации (т.е. вход или выход). Это похоже на работу для нового и блестящего React Context. Это именно то, что мы собираемся использовать!

Сохранение состояния авторизации

Поскольку мы еще не показали, как выглядит контейнер приложения верхнего уровня, давайте посмотрим на снимок «до». Поверьте мне, скоро это станет намного сексуальнее ;)

Я не буду вдаваться в подробности того, как работает React Context, а вместо этого объясню, какой функционал здесь нам нужен.

  1. Наш контейнер приложения верхнего уровня должен поддерживать часть состояния о том, аутентифицирован ли текущий пользователь или нет. Это приведет к тому, что RootNavigator покажет правильный макет, основанный на аутентифицированном состоянии.
  2. Любой дочерний элемент, выполняющий функцию, связанную с аутентификацией (например, Login, Signup или Signout), должен иметь возможность обновлять состояние аутентификации с помощью обратного вызова.

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

Что мы здесь добавили? Во-первых, мы добавили логическое значение isAuthenticated в состояние, которое отслеживает, аутентифицирован ли текущий пользователь (да!). Во-вторых, мы также добавили вызов currentSession из библиотеки Amplify. Это попытка обновить предыдущий аутентифицированный сеанс без написания кода. Сладкий!

Теперь давайте подключим Context, чтобы компонент Login мог обновлять это состояние. Мы добавим весь код, связанный с контекстом, в отдельный файл, как показано ниже. Это может показаться знакомым (или нет), но я объясню, что мы здесь делали, шаг за шагом.

Далее мы будем использовать AuthContext в контейнере приложения. Единственное, что нам нужно сделать, это обернуть AppContainer провайдером контекста, как показано здесь (мы показываем только метод render для краткости):

Метод setAuthenticated — это просто установщик для isAuthenticated.

Последний шаг: использование контекста в компоненте Login. Здесь мы будем использовать withAuthContext HOC, который мы еще не обсуждали. Это действительно простой способ использовать потребитель контекста в любом компоненте, который мы хотим. Вот как теперь выглядит метод handleSubmit в компоненте Login:

Нам также нужно экспортировать компонент, используя withAuthContext HOC:

В ПОРЯДКЕ. Пауза. Дышать.

Что мы только что сделали? Используя React Context, мы можем получить доступ к методу setAuthenticated контейнера приложения верхнего уровня, который доступен в качестве реквизита. Вызов этого с true в качестве параметра установит isAuthenticated в true, что, в свою очередь, вызовет SwitchNavigator для отображения макета Authenticated. Бум! Вот он в действии:

Выход

Когда пользователь нажимает кнопку «Выход», должны произойти две вещи: (а) вызвать соответствующий метод в Amplify, чтобы очистить активный сеанс на серверной части, и (б) обновить флаг isAuthenticated в нашем состоянии. К счастью, у нас есть все инструменты, необходимые для того и другого. Вот как сейчас выглядит экран Home:

Как и в приведенном выше примере Login, установка isAuthenticated на true после успешного signOut, SwitchNavigator заботится о перенаправлении нас на макет Unauthenticated. Сделано и сделано.

Примечание об AWS Amplify

Есть еще более простой способ сделать это, если вы планируете использовать AWS Cognito в качестве поставщика инфраструктуры как услуги. В документации гораздо больше подробностей, но вкратце, вы можете просто позволить библиотеке AWS Amplify сделать почти все вышеперечисленное за вас, показывая все необходимые экраны (включая экраны 2FA и т. д.).

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

Вау, это было долго. Надеюсь, это было также довольно полезно. Спасибо, что остаётесь со мной! Далее мы рассмотрим некоторые интересные функции из набора инструментов Expo, такие как получение информации о местоположении. Увидимся там!

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

Обо мне

Я Алекс, инженер-программист и фанат стартапов. В настоящее время я являюсь соучредителем стартапа AgentRisk, где я являюсь вице-президентом по продукту и разработке. В прошлой жизни я был частью команды инженеров-основателей в стартапе корпоративных облачных хранилищ в Силиконовой долине, делал кучу крутых передовых проектов в Cisco Research и работал над действительно инновационной сетью центров обработки данных. архитектуры» во время учебы в магистратуре Калифорнийского университета в Сан-Франциско. Мне всегда нравится изучать новые технологии и постоянно заниматься поставками сторонних проектов.