Аутентификация пользователей для веб-приложений и приложений для iOS с помощью AWS Cognito (часть 1)
Опубликовано: 2022-03-10За эти годы я создал с нуля как минимум три системы управления пользователями. Большая часть подхода может быть основана на шаблоне, но всегда есть несколько ключевых элементов, которые необходимо настроить для конкретного клиента. Это настолько серьезно, что для удовлетворения этой потребности возникла целая категория служб управления пользователями, аутентификации и авторизации. Такие службы, как Auth0, имеют целые решения, основанные на управлении пользователями и идентификацией, с которыми разработчики могут интегрироваться.
Одной из служб, предоставляющих эту функциональность, является Amazon Web Services (AWS) Cognito. Cognito — это инструмент, позволяющий пользователям регистрироваться и входить в веб-приложения и мобильные приложения , которые вы создаете. В дополнение к этой функциональности он также позволяет хранить пользовательские данные в автономном режиме и обеспечивает синхронизацию этих данных. Как заявляет Amazon: «С Amazon Cognito вы можете сосредоточиться на создании отличных приложений, вместо того чтобы беспокоиться о создании, защите и масштабировании решения для управления пользователями, аутентификации и синхронизации между устройствами».
Недооценка каруселей
Карусели на самом деле не заслуживают той плохой репутации, которую они приобрели на протяжении многих лет. Они могут оказаться очень эффективными и бывают разных форм и размеров. Читать статью по теме →
В прошлом году Amazon представила дополнение к своему сервису Cognito — пользовательские пулы пользователей. Эта функциональность теперь обеспечивает то, что нужно мне и другим разработчикам, чтобы иметь полную, настраиваемую, кросс-платформенную систему управления пользователями с гибкостью, необходимой для большинства случаев использования. Чтобы понять почему, нам нужно бросить беглый взгляд на то, что такое управление пользователями и какие проблемы оно решает.
В этой статье мы потратим большую часть времени на процесс настройки пула пользователей для наших нужд. Затем мы интегрируем этот пул пользователей с приложением iOS и позволим пользователю войти в систему и получить атрибуты, связанные с его учетной записью пользователя. К концу у нас будет ограниченное демонстрационное приложение, но оно будет обрабатывать ядро управления пользователями. Кроме того, после того, как это будет сделано, будет следующая статья, в которой это будет рассмотрено немного глубже.
Что нам нужно от управления пользователями?
Если у вас есть мобильное или веб-приложение, что именно вам нужно с точки зрения управления пользователями? Хотя вход пользователя в систему — это, вероятно, первое, о чем вы подумали, мы не можем останавливаться на достигнутом. Если нам нужна гибкая система управления пользователями, которая будет работать в большинстве случаев использования веб-приложений и мобильных приложений, она должна иметь следующие функции:
- логин и пароль для входа;
- безопасное хэширование и хранение паролей;
- смена пароля;
- политика паролей и проверка;
- триггеры жизненного цикла пользователя (приветственное письмо, прощальное письмо и т. д.);
- атрибуты пользователя (имя, фамилия и т. д.);
- требуемая конфигурация и дополнительные атрибуты для каждого пользователя;
- обработка забытых паролей;
- подтверждение номера телефона через SMS;
- подтверждение адреса электронной почты;
- API-доступ к конечным точкам на основе разрешений;
- безопасное хранение токенов доступа на мобильных устройствах;
- автономное хранение пользовательских атрибутов для мобильных устройств;
- синхронизация пользовательских атрибутов для онлайн- и офлайн-состояний;
- многофакторная аутентификация.
Хотя на первый взгляд управление пользователями может показаться системой входа в систему, функциональность должна выходить далеко за рамки этого, чтобы система была действительно достаточно гибкой для обработки большинства вариантов использования. Это явно выходит далеко за рамки простого имени пользователя и пароля.
Здесь необходимо упомянуть еще один пункт: безопасность. Одно из требований к любой системе управления пользователями заключается в том, что ее необходимо постоянно оценивать с точки зрения безопасности системы в целом. Многие пользовательские системы управления пользователями имеют уязвимости, которые просто не были исправлены. За последний год имели место нарушения безопасности систем управления пользователями таких компаний, как Dropbox, Dailymotion, Twitter и Yahoo. Если вы решите создать индивидуальное решение, вы встанете на крючок для обеспечения безопасности вашей системы.
Войдите в Amazon Cognito
Amazon Cognito — это управляемый сервис, позволяющий интегрировать гибкую и масштабируемую систему управления пользователями в веб-приложения и мобильные приложения. Cognito предлагает два разных способа использования сервиса: федеративные удостоверения, которые позволяют входить в систему через социальные сети, такие как Facebook, и пулы пользователей, которые дают вам полностью настраиваемые возможности управления пользователями для конкретного приложения или набора приложений.
Федеративные удостоверения хороши, если вы хотите, чтобы пользователи могли входить в систему через Facebook (или Google, Amazon и т. д.), но это означает, что часть процесса управления пользователями будет передана Facebook на аутсорсинг. Хотя в некоторых случаях это может быть приемлемо, пользователи могут не захотеть подключать свои учетные записи Facebook к вашему приложению. Кроме того, вы можете захотеть управлять большей частью жизненного цикла пользователя напрямую, и для этого федеративные удостоверения не так гибки. В целях сегодняшней статьи мы сосредоточимся на пулах пользователей, поскольку они обеспечивают гибкость, необходимую для надежной платформы управления пользователями, которая подходит практически для любого случая использования. Таким образом, у вас будет подход, который можно использовать практически в любом проекте.
Поскольку это сервис AWS, у Cognito есть и другие преимущества. Cognito может интегрироваться со шлюзом API, чтобы обеспечить безболезненный способ авторизации доступа к API на основе токенов, возвращаемых при входе в систему Cognito. Кроме того, если вы уже используете другие сервисы AWS для своего мобильного приложения, вы можете использовать свой пользовательский пул в качестве поставщика удостоверений для своих учетных данных AWS.
Как и в случае с любым другим сервисом AWS, это связано с затратами. Цены на Cognito основаны на количестве активных пользователей в месяц (MAU). Хорошая новость для большинства разработчиков заключается в том, что существует бессрочный уровень бесплатного пользования, ограниченный 50 000 MAU при использовании пользовательского пула пользователей. Если у вас большое приложение, это даст вам большое количество пользователей, чтобы протестировать новый подход к управлению пользователями. Однако я подозреваю, что у многих из вас есть опыт, который никогда не превысит 50 000 пользователей. В этом случае основное управление пользователями будет практически бесплатным. Единственным исключением являются другие сервисы AWS, которые вы будете использовать в рамках процесса управления пользователями, такие как Lambda, SNS и S3.
Создание пула пользователей
Первым шагом в интеграции пула пользователей в ваше мобильное приложение является создание пула пользователей Cognito. Это даст нам значения конфигурации, необходимые для подключения к нашему примерному приложению. Чтобы создать новый пул пользователей, воспользуйтесь мастером, представленным в консоли Amazon Cognito.
Давайте рассмотрим процесс создания пула пользователей. Должен предупредить, что это длительный процесс. Во многих отношениях это хорошо, потому что показывает области гибкости. Тем не менее, вам захочется выпить чашку кофе и пристегнуться.
1. Имя
Начальный шаг в создании пула пользователей включает установку имени для вашего пула пользователей и выбор подхода, который вы будете использовать для создания пула пользователей. Вы можете либо просмотреть значения по умолчанию, либо «пройтись» по настройкам. Поскольку мы хотим иметь хорошие практические знания о том, как настраивается пул пользователей, выберите параметр «Пошаговые настройки».
2. Атрибуты
Настройка атрибутов потребует немного размышлений. Для каждого пула пользователей вам нужно будет определить, какие атрибуты будут храниться в системе, а какие необходимы. Поскольку система будет применять требуемые значения, вы не сможете изменить это в будущем. Наилучший подход здесь — отметить только действительно важные значения как требуемые. Кроме того, если вы хотите, чтобы пользователи могли входить в систему со своим адресом электронной почты, обязательно пометьте его как псевдоним.
Если вы хотите включить пользовательские значения, вам также нужно будет сделать это здесь. Каждое пользовательское значение будет иметь тип, необязательные правила проверки и возможность быть изменяемым (изменяемым) или неизменяемым (неизменяемым). Существует жесткое ограничение в 25 настраиваемых атрибутов.
Наконец, здесь необходимо сделать замечание об именах пользователей. Значение имени пользователя для каждого пользователя является неизменным (неизменяемым). Это означает, что в большинстве случаев имеет смысл сделать это значение автоматически генерируемым. Вот почему существует значение «предпочтительное имя пользователя». Если вы хотите, чтобы у пользователей было значение имени пользователя, которое они могли редактировать, просто отметьте атрибут «предпочтительное имя пользователя» как псевдоним. Если вы хотите, чтобы пользователи просто входили в систему со своим адресом электронной почты, обязательно отметьте атрибут «email» как обязательный и как псевдоним.
Для нашего демонстрационного приложения я решил сделать обязательными «электронную почту», «имя» и «фамилию».
3. Политика
После настройки атрибутов вы сможете настроить политики для учетной записи. Первая политика, которую необходимо настроить, — это политика паролей. Политика позволяет настроить как длину, так и требуемые цифры, специальные символы, прописные или строчные буквы. Эта политика будет применяться как к паролям, которые вводят пользователи, так и к паролям, которые администраторы назначают пользователям.
Следующие политики относятся к регистрации пользователей. Для общедоступного приложения вы, вероятно, захотите разрешить пользователям регистрироваться самостоятельно. Однако, в зависимости от типа приложения, вы можете ограничить регистрацию и сделать систему доступной только по приглашению. Кроме того, вам придется настроить, как быстро истечет срок действия этих приглашений, если они не используются.
Для нашего демонстрационного приложения я решил использовать только значения по умолчанию, за исключением того, что я не хочу, чтобы пользователи могли регистрироваться самостоятельно. Имея эти значения, мы можем перейти к проверкам.
4. Проверки
Шаг проверки позволяет настроить многофакторную аутентификацию, а также проверку электронной почты и телефона. Хотя эту функцию относительно легко настроить в консоли, обратите внимание, что вам нужно будет запросить увеличение расходов на AWS SNS, если вы хотите подтвердить номера телефонов или использовать многофакторную аутентификацию.
Для нашего демонстрационного приложения я решил использовать только значения по умолчанию.
5. Настройки сообщений
Этот шаг позволяет вам настроить сообщения электронной почты и SMS, которые будет отправлять ваш пользовательский пул, а также адреса электронной почты «от» и «ответить на». Для целей нашего демонстрационного приложения я оставлю здесь значения по умолчанию и продолжу.
6. Теги
Если вы новичок в AWS, вам может не понадобиться указывать какие-либо теги. Однако если ваша организация регулярно использует AWS, теги позволяют анализировать расходы и назначать разрешения с помощью IAM. Например, некоторые организации указывают теги для каждой среды (разработка, подготовка, производство) и проекта.
Независимо от того, что вы введете на этом шаге, это не повлияет на наше демонстрационное приложение.
7. Устройства
Следующий шаг позволяет вам определить, будет ли пул пользователей запоминать устройства вашего пользователя. Это дополнительный шаг безопасности, который позволяет вам видеть, с каких устройств был выполнен вход в конкретную учетную запись. Это имеет дополнительное значение, когда вы используете многофакторную аутентификацию (MFA). Если устройство запоминается, вы можете выбрать не запрашивать токен MFA при каждом входе в систему.
Для демонстрационного приложения я решил установить значение «Всегда».
8. Клиенты приложений
Для каждого приложения, для которого вы хотите использовать пул пользователей (например, приложение для iOS, веб-приложение, приложение для Android и т. д.), вы должны создать приложение. Тем не менее, вы можете вернуться и создать их после создания пула пользователей, поэтому пока нет острой необходимости добавлять все это.
Каждое приложение имеет несколько значений, которые вы можете настроить. Для этого демонстрационного приложения мы дадим приложению имя, а затем оставим значения по умолчанию. Затем вы можете настроить, какие пользовательские атрибуты каждое приложение может читать и записывать.
На этом шаге вы можете установить любые значения, которые вам нравятся, при условии, что адрес электронной почты, фамилия и имя доступны для чтения и записи приложением. Прежде чем продолжить, обязательно выберите опцию «Создать клиент приложения».
9. Триггеры
С помощью триггеров вы можете использовать функции Lambda для полной настройки процесса жизненного цикла пользователя. Например, если вы хотите, чтобы пользователи с адресом электронной почты из домена вашей компании могли зарегистрироваться, вы можете добавить функцию Lambda для триггера «Предварительная регистрация», чтобы выполнить эту проверку и отклонить любой запрос на регистрацию, который не проходит.
Для нашего демонстрационного приложения я не буду добавлять никаких триггеров.
10. Обзор
Я понимаю, что это могло показаться длительным и трудным процессом. Но имейте в виду, что каждый шаг в создании пула пользователей отличается гибкостью, что позволяет использовать решение для большего количества вариантов использования. А теперь новость, которую вы так долго ждали: это последний шаг.
Просто просмотрите настройки, чтобы убедиться, что вы правильно настроили их для демонстрационного приложения. На этом экране вы можете вернуться и отредактировать любую из предыдущих настроек. После создания пула пользователей некоторые значения конфигурации (например, обязательные атрибуты) изменить нельзя.
Создав новый пул пользователей, вы можете приступить к их интеграции в пример приложения iOS с помощью AWS SDK для iOS.
Настройка приложения iOS для вашего пула пользователей
Я создал пример приложения для iOS, которое интегрируется с Cognito, чтобы позволить пользователю входить в систему, выходить из системы, вводить свое имя и фамилию и устанавливать пароль. В этой первоначальной демонстрации регистрация пользователя не включена, поэтому я использовал консоль Cognito, чтобы добавить нового пользователя для тестирования.
Код этого приложения можно найти в моем репозитории GitHub.
Настройка зависимостей
Это приложение использует CocoaPods для управления зависимостями. На данный момент единственными зависимостями являются определенные части AWS iOS SDK, относящиеся к пулам пользователей Cognito.
(Полное описание CocoaPods выходит за рамки этой статьи, однако ресурс на веб-сайте CocoaPods поможет вам приступить к работе, если эта концепция для вас нова.)
Содержимое подфайла для этого приложения можно увидеть ниже:
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'CognitoApplication' do pod 'AWSCore', '~> 2.5.5' pod 'AWSCognitoIdentityProvider', '~> 2.5.5' end
Предполагая, что CocoaPods установлен на вашем компьютере, вы можете просто запустить pod install
, и необходимые зависимости будут установлены для вас.
Конфигурация пула пользователей
Следующим шагом является включение значений для вашего пользовательского пула и клиентского приложения. Демонстрационное приложение настроено на использование файла CognitoApplication/CognitoConfig.plist
, из которого можно извлечь эту информацию. Необходимо определить четыре значения:
-
region
(строка)
Это регион, в котором вы создали свой пользовательский пул. Это должен быть стандартный идентификатор региона, напримерus-east-1
илиap-southeast-1
. -
poolId
(строка)
Это идентификатор созданного вами пула пользователей. -
clientId
(строка)
ЭтоclientId
, настроенный как часть приложения, которое вы присоединили к пулу пользователей. -
clientSecret
(строка)
ЭтоclientSecret
, настроенный как часть приложения, которое вы присоединили к пулу пользователей.
С этим файлом и правильными значениями можно запустить демонстрационное приложение. Если во время запуска возникают какие-либо исключения, убедитесь, что вы включили каждое из четырех значений, показанных ниже, и что файл находится в правильном каталоге.
Интеграция делегата приложения
В основе интеграции с Amazon Cognito лежит AppDelegate
приложения. Наш первый шаг — убедиться, что мы настроили ведение журнала и подключились к нашему пулу пользователей. В рамках этого процесса мы назначим наш AppDelegate
в качестве делегата пула пользователей. В этом базовом примере мы можем сохранить эту логику в AppDelegate
. Для более крупных проектов может иметь смысл заняться этим в другом месте.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // set up logging for AWS and Cognito AWSDDLog.sharedInstance.logLevel = .verbose AWSDDLog.add(AWSDDTTYLogger.sharedInstance) // set up Cognito config self.cognitoConfig = CognitoConfig() // set up Cognito setupCognitoUserPool() return true } func setupCognitoUserPool() { // we pull the needed values from the CognitoConfig object // this just pulls the values in from the plist let clientId:String = self.cognitoConfig!.getClientId() let poolId:String = self.cognitoConfig!.getPoolId() let clientSecret:String = self.cognitoConfig!.getClientSecret() let region:AWSRegionType = self.cognitoConfig!.getRegion() // we need to let Cognito know which region we plan to connect to let serviceConfiguration:AWSServiceConfiguration = AWSServiceConfiguration(region: region, credentialsProvider: nil) // we need to pass it the clientId and clientSecret from the app and the poolId for the user pool let cognitoConfiguration:AWSCognitoIdentityUserPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: clientId, clientSecret: clientSecret, poolId: poolId) AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: cognitoConfiguration, forKey: userPoolID) let pool:AWSCognitoIdentityUserPool = AppDelegate.defaultUserPool() // we need to set the AppDelegate as the user pool's delegate, which will get called when events occur pool.delegate = self }
После того, как эта конфигурация создана, нам нужно настроить методы делегата для пула пользователей. Протокол, который мы реализуем, — AWSCognitoIdentityInteractiveAuthenticationDelegate
. Этот делегат будет вызываться каждый раз, когда пользователю необходимо войти в систему, сбросить свой пароль или предоставить код многофакторной аутентификации, или если нам нужно запросить пользователя о том, хочет ли он, чтобы его устройство запомнилось. В нашем примере нам нужно только реализовать startPasswordAuthentication
и startNewPasswordRequired
:
extension AppDelegate: AWSCognitoIdentityInteractiveAuthenticationDelegate { // This method is called when we need to log into the application. // It will grab the view controller from the storyboard and present it. func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication { if(self.navigationController == nil) { self.navigationController = self.window?.rootViewController as? UINavigationController } if(self.loginViewController == nil) { self.loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as? LoginViewController } DispatchQueue.main.async { if(self.loginViewController!.isViewLoaded || self.loginViewController!.view.window == nil) { self.navigationController?.present(self.loginViewController!, animated: true, completion: nil) } } return self.loginViewController! } // This method is called when we need to reset a password. // It will grab the view controller from the storyboard and present it. func startNewPasswordRequired() -> AWSCognitoIdentityNewPasswordRequired { if (self.resetPasswordViewController == nil) { self.resetPasswordViewController = self.storyboard?.instantiateViewController(withIdentifier: "ResetPasswordController") as? ResetPasswordViewController } DispatchQueue.main.async { if(self.resetPasswordViewController!.isViewLoaded || self.resetPasswordViewController!.view.window == nil) { self.navigationController?.present(self.resetPasswordViewController!, animated: true, completion: nil) } } return self.resetPasswordViewController! } }
Важно отметить, что оба этих метода возвращают контроллер представления, который реализует определенный протокол. Например, LoginViewController
реализует AWSCognitoIdentityPasswordAuthentication
с единственным методом, который вызывается с параметрами, необходимыми для того, чтобы пользователь мог завершить процесс входа в систему.
Поток аутентификации
Теперь, когда все эти элементы размещены в демонстрационном приложении, вы можете увидеть процесс входа в систему от начала до конца. Основной вид приложения показывает имя пользователя, имя и фамилию пользователя. Чтобы это произошло, выполняются следующие шаги:
- В
AppViewController
мы вызываем методfetchUserAttributes
в методеviewDidLoad
. Если пользователь не вошел в систему, это инициирует процесс входа в систему. - Будет запущен метод
startPasswordAuthentication
вAppDelegate
. Этот метод загружаетLoginViewController
и представляет его. - Метод
getDetails
LoginViewController
вызывается AWS SDK. Сюда входит объект, являющийся экземпляромAWSTaskCompletionSource
, который мы можем использовать, чтобы позволить пользователю попытаться войти в систему. - Когда пользователь нажимает кнопку «Войти», мы передаем учетные данные для входа в этот объект. Это вызовет метод
didCompleteStepWithError
, и мы сможем соответствующим образом обработать результат. Если ошибки нет, мы можем закрыть контроллер представления. - Если мы создали пользователя в консоли, у нас будет еще один шаг для обработки здесь. Поскольку мы предоставили пользователю временный пароль, ему нужно будет установить более постоянный пароль. Кроме того, поскольку мы устанавливаем имя и фамилию в качестве обязательных параметров, нам также необходимо разрешить пользователю вводить их. AWS SDK обнаружит это и вызовет метод
startNewPasswordRequired
вAppDelegate
. Это представитResetPasswordViewController
и установит его экземплярAWSTaskCompletionSource
. -
ResetPasswordViewController
работает почти так же, какLoginViewController
. Нам просто нужно запросить у пользователя правильные значения, а затем отправить эти значения. Как только этот процесс завершится успешно, мы закроем контроллер представления. - После завершения всего процесса входа в систему SDK надежно сохранит токены, возвращенные Cognito. Затем мы, наконец, получим данные пользователя и сможем использовать их для заполнения
AppViewController
именем пользователя, именем и фамилией.
Заключение
Хотя процесс настройки пула пользователей может состоять из нескольких шагов, по этим шагам легко ориентироваться. Кроме того, объем возможных конфигураций должен дать вам уверенность в том, что он может поддерживать большинство вариантов использования. В своей основной работе в Universal Mind я работал с несколькими клиентами, которые переносили свои существующие приложения, чтобы использовать возможности, предоставляемые Cognito для управления пользователями.
Независимо от того, нужно ли вам регулярно внедрять систему управления пользователями, это инструмент, который каждый мобильный и веб-разработчик должен иметь в своем наборе инструментов . В следующей статье этой серии мы начнем немного больше изучать возможности Cognito, реализуя более полнофункциональное демонстрационное приложение, которое реализует больше распространенных вариантов использования для управления пользователями.
Немного потренировавшись, вы сможете произвести впечатление на всех своих друзей, настроив новое приложение, удовлетворяющее всем этим сценариям использования для управления пользователями, за один день. Это неплохо для дневной работы.
Ссылки и ресурсы
- Амазон Когнито
- «Ресурсы для разработчиков», Amazon Cognito
- SDK для мобильных устройств AWS
- «Учебное пособие по CocoaPods для Swift: начало работы», Джошуа Грин, raywenderlich.com