Autenticação do usuário para aplicativos da Web e iOS com o AWS Cognito (parte 1)

Publicados: 2022-03-10
Resumo rápido ↬ Desenvolvedores e organizações estão procurando uma maneira de ter mais agilidade com soluções móveis. Há um desejo de diminuir o tempo da ideia ao teste. Como desenvolvedor, muitas vezes me deparo com um obstáculo que pode retardar a construção inicial de uma hipótese móvel: gerenciamento de usuários.

Ao longo dos anos, construí pelo menos três sistemas de gerenciamento de usuários do zero. Grande parte da abordagem pode ser baseada em um clichê, mas sempre há alguns itens importantes que precisam ser personalizados para um cliente específico. Isso é uma preocupação suficiente para que toda uma categoria de serviços de gerenciamento, autenticação e autorização de usuários tenha surgido para atender a essa necessidade. Serviços como Auth0 têm soluções inteiras baseadas em gerenciamento de usuários e identidades com as quais os desenvolvedores podem se integrar.

Um serviço que fornece essa funcionalidade é o Cognito da Amazon Web Services (AWS). O Cognito é uma ferramenta para permitir que os usuários se inscrevam e entrem em aplicativos da Web e móveis que você cria. Além dessa funcionalidade, também permite o armazenamento offline de dados do usuário e fornece sincronização desses dados. Como a Amazon afirma: “Com o Amazon Cognito, você pode se concentrar na criação de ótimas experiências de aplicativos em vez de se preocupar em criar, proteger e dimensionar uma solução para lidar com o gerenciamento de usuários, autenticação e sincronização entre dispositivos”.

Subestimando carrosséis

Carrosséis realmente não merecem a má reputação que ganharam ao longo dos anos. Eles podem provar ser muito eficazes e vêm em muitas formas e tamanhos. Leia um artigo relacionado →

No ano passado, a Amazon introduziu uma adição ao seu serviço Cognito, grupos de usuários personalizados. Essa funcionalidade agora fornece o que eu e outros desenvolvedores precisamos para ter um sistema de gerenciamento de usuários completo, personalizável e multiplataforma, com a flexibilidade necessária para se adequar à maioria dos casos de uso. Para entender o porquê, precisamos dar uma olhada rápida no que é o gerenciamento de usuários e quais problemas ele resolve.

Mais depois do salto! Continue lendo abaixo ↓
AWS Cognito
Diagrama de grupo de usuários personalizado do Cognito (Ver versão ampliada)

Neste artigo, passaremos a maior parte do tempo percorrendo o processo de configuração de um grupo de usuários para nossas necessidades. Em seguida, integraremos esse grupo de usuários a um aplicativo iOS e permitiremos que um usuário faça login e busque os atributos associados à sua conta de usuário. No final, teremos um aplicativo de demonstração limitado, mas que trata do núcleo do gerenciamento de usuários. Além disso, depois que isso estiver em vigor, haverá um artigo de acompanhamento que levará isso um pouco mais a fundo.

O que precisamos do gerenciamento de usuários?

Se você tem um aplicativo móvel ou web, o que exatamente você precisa em termos de gerenciamento de usuários? Embora o login do usuário seja provavelmente a primeira coisa que você pensaria, não podemos parar por aí. Se quisermos um sistema de gerenciamento de usuários flexível que funcione para a maioria dos casos de uso de aplicativos móveis e da Web, ele precisaria ter a seguinte funcionalidade:

  • login de usuário e senha;
  • hash e armazenamento seguro de senhas;
  • alterações de senha;
  • política e validação de senha;
  • gatilhos do ciclo de vida do usuário (e-mail de boas-vindas, e-mail de adeus, etc.);
  • atributos do usuário (nome, sobrenome, etc.);
  • configuração necessária e atributos opcionais por usuário;
  • tratamento de senhas esquecidas;
  • validação do número de telefone por SMS;
  • verificação de e-mail;
  • Acesso de API a endpoints com base em permissões;
  • armazenamento seguro de token(s) de acesso em dispositivos móveis;
  • armazenamento offline de atributos de usuário para dispositivos móveis;
  • sincronização de atributos de usuário para estados online e offline;
  • autenticação multifator.

Embora o gerenciamento de usuários possa parecer a princípio um sistema de login, a funcionalidade deve ir muito além disso para que o sistema seja realmente flexível o suficiente para lidar com a maioria dos casos de uso. Isso claramente vai muito além de apenas um nome de usuário e senha.

Um item adicional precisa ser destacado aqui: segurança. Um dos requisitos de qualquer sistema de gerenciamento de usuários é que ele precisa ser continuamente avaliado para a segurança do sistema como um todo. Muitos sistemas de gerenciamento de usuários personalizados têm vulnerabilidades que simplesmente não foram corrigidas. No ano passado, houve violações de segurança dos sistemas de gerenciamento de usuários de empresas como Dropbox, Dailymotion, Twitter e Yahoo. Se você optar por construir uma solução customizada, você estará no gancho para proteger seu sistema.

Entre no Amazon Cognito

O Amazon Cognito é um serviço gerenciado que permite integrar um sistema de gerenciamento de usuários flexível e escalável em seus aplicativos web e móveis. O Cognito fornece duas maneiras distintas de utilizar o serviço: identidades federadas, que permitem o login por meio de redes sociais como o Facebook, e grupos de usuários, que oferecem recursos de gerenciamento de usuários totalmente personalizados para um aplicativo ou conjunto de aplicativos específico.

As identidades federadas são ótimas se você deseja que os usuários possam fazer login com o Facebook (ou Google, Amazon etc.), mas isso significa que uma parte do processo de gerenciamento de usuários será terceirizada para o Facebook. Embora isso possa ser aceitável em alguns casos, os usuários podem não querer conectar sua conta do Facebook ao seu aplicativo. Além disso, você pode querer gerenciar mais do ciclo de vida do usuário diretamente e, para isso, as identidades federadas não são tão flexíveis. Para os propósitos do artigo de hoje, vamos nos concentrar nos grupos de usuários porque eles fornecem a flexibilidade necessária para uma plataforma robusta de gerenciamento de usuários que se encaixa em quase todos os casos de uso. Dessa forma, você terá uma abordagem que pode ser usada na maioria dos projetos.

Como este é um serviço da AWS, há outros benefícios de usar o Cognito. O Cognito pode se integrar ao API Gateway para fornecer uma maneira fácil de autorizar o acesso à API com base nos tokens retornados de um login do Cognito. Além disso, se você já estiver aproveitando outros serviços da AWS para seu aplicativo móvel, poderá usar seu grupo de usuários como um provedor de identidade para suas credenciais da AWS.

Como em qualquer outro serviço da AWS, há um custo envolvido. O preço do Cognito é baseado em usuários ativos mensais (MAUs). A grande notícia para a maioria dos desenvolvedores é que há um nível gratuito indefinido limitado a 50.000 MAUs ao usar um grupo de usuários personalizado. Se você tiver um aplicativo grande, isso fornecerá um grande número de usuários para pilotar uma nova abordagem de gerenciamento de usuários. No entanto, suspeito que muitos de vocês tenham experiências que nunca ultrapassarão 50.000 usuários. Nesse caso, o gerenciamento de usuários principais será praticamente gratuito. A única exceção a isso são outros serviços da AWS que você aproveitará como parte do processo de gerenciamento de usuários, como Lambda, SNS e S3.

Criando um grupo de usuários

A primeira etapa na integração de um grupo de usuários em seu aplicativo móvel é criar um grupo de usuários Cognito. Isso nos dará os valores de configuração necessários para conectar ao nosso aplicativo de exemplo. Para criar um novo grupo de usuários, percorra o assistente fornecido no console Cognito da Amazon.

Vamos percorrer o processo de criação de um grupo de usuários. Devo avisá-lo que este é um processo demorado. De muitas maneiras, isso é bom porque mostra áreas de flexibilidade. No entanto, você vai querer pegar uma xícara de café e se preparar para esta.

1. Nome

A etapa inicial na criação de um grupo de usuários envolve definir um nome para seu grupo de usuários e selecionar a abordagem que você adotará para criar o grupo de usuários. Você pode revisar os padrões ou “percorrer” as configurações. Como queremos ter um bom conhecimento prático de como o grupo de usuários está sendo configurado, escolha a opção "Percorrer as configurações".

Etapa 1 na criação do grupo de usuários
A etapa inicial na criação de um grupo de usuários (Ver versão grande)

2. Atributos

A configuração de atributos exigirá um pouco de reflexão. Para cada grupo de usuários, você precisará determinar quais atributos serão armazenados no sistema e quais são necessários. Como o sistema aplicará os valores obrigatórios, você não poderá alterar isso no futuro. A melhor abordagem aqui é marcar apenas valores verdadeiramente essenciais aqui, conforme necessário. Além disso, se você quiser que os usuários possam fazer login com seus endereços de e-mail, certifique-se de marcá-los como um alias.

Se você quiser incluir valores personalizados, precisará fazer isso aqui também. Cada valor personalizado terá um tipo, regras de validação opcionais e uma opção para ser mutável (alterável) ou não mutável (inalterável). Há um limite rígido de 25 atributos personalizados.

Finalmente, um ponto precisa ser feito aqui sobre nomes de usuário. O valor do nome de usuário para cada usuário é imutável (imutável). Isso significa que, na maioria dos casos, fazer esse valor gerado automaticamente faria sentido. É por isso que o valor "nome de usuário preferencial" existe. Se você quiser que os usuários tenham um valor de nome de usuário que eles possam editar, basta marcar o atributo “nome de usuário preferido” como um alias. Se você quiser que os usuários simplesmente façam login com seus endereços de e-mail, certifique-se de marcar o atributo “email” como obrigatório e um alias.

Para nosso aplicativo de demonstração, optei por tornar obrigatórios “e-mail”, “nome próprio” e “nome de família”.

Etapa 2 na criação do grupo de usuários
Configurando atributos de usuário para o grupo de usuários (Ver versão grande)

3. Políticas

Depois de configurar os atributos, você poderá configurar as políticas para a conta. A primeira política a ser configurada é a política de senha. A política permite configurar o comprimento e se você precisa de números, caracteres especiais, letras maiúsculas ou minúsculas. Esta política será aplicada tanto nas senhas que os usuários inserem quanto nas senhas que os administradores atribuem aos usuários.

As próximas políticas estão relacionadas à inscrição do usuário. Para um aplicativo público, você provavelmente desejará permitir que os usuários se inscrevam. No entanto, dependendo do tipo de aplicativo, talvez você queira restringir a inscrição e fazer com que o sistema seja apenas para convidados. Além disso, você terá que configurar a rapidez com que esses convites expirarão se não forem usados.

Para nosso aplicativo de demonstração, optei por usar apenas os valores padrão, com a exceção de que não quero que os usuários possam se inscrever por conta própria. Com esses valores em vigor, podemos proceder às verificações.

Etapa 3 na criação do grupo de usuários
Configurando políticas para o grupo de usuários (Ver versão grande)

4. Verificações

A etapa de verificações permite configurar a autenticação multifator, bem como a verificação de e-mail e telefone. Embora essa funcionalidade seja relativamente fácil de configurar no console, observe que você precisará solicitar um aumento de gastos para o AWS SNS se quiser verificar números de telefone ou usar autenticação multifator.

Para nosso aplicativo de demonstração, optei por usar apenas os valores padrão.

Etapa 4 na criação do grupo de usuários
Configurando verificações para o grupo de usuários (Ver versão grande)

5. Personalizações de mensagens

Esta etapa permite que você personalize as mensagens de e-mail e SMS que seu grupo de usuários enviará, bem como os endereços de e-mail “de” e “responder a”. Para fins de nosso aplicativo de demonstração, deixarei os valores padrão aqui e prosseguirei.

Etapa 5 na criação do grupo de usuários
Configurando as mensagens de ciclo de vida para o grupo de usuários (Ver versão grande)

6. Etiquetas

Se você é novo na AWS, talvez não precise especificar nenhuma tag. No entanto, caso sua organização use a AWS regularmente, as tags fornecem uma maneira de analisar gastos e atribuir permissões com o IAM. Por exemplo, algumas organizações especificam tags por ambiente (desenvolvimento, preparação, produção) e por projeto.

Não importa o que você insira nesta etapa, isso não afetará nosso aplicativo de demonstração.

Etapa 6 na criação do grupo de usuários
Adicionando tags para o grupo de usuários (Ver versão grande)

7. Dispositivos

A próxima etapa permite definir se o grupo de usuários lembrará os dispositivos do seu usuário. Esta é uma etapa de segurança adicional que permite que você veja em quais dispositivos uma conta específica foi conectada. Isso tem um valor extra quando você está aproveitando a autenticação multifator (MFA). Se o dispositivo for lembrado, você pode optar por não exigir um token MFA em cada login.

Para fins do aplicativo de demonstração, optei por definir o valor como "Sempre".

Etapa 7 na criação do grupo de usuários
Configurando o manuseio de dispositivos para o grupo de usuários (Ver versão grande)

8. Clientes de aplicativos

Para cada aplicativo para o qual você deseja usar o grupo de usuários (como um aplicativo iOS, aplicativo da Web, aplicativo Android etc.), você deve criar um aplicativo. No entanto, você pode voltar e criá-los após a criação do grupo de usuários, portanto, não há necessidade urgente de adicionar todos eles ainda.

Cada aplicativo tem vários valores que você pode configurar. Para este aplicativo de demonstração, daremos um nome ao aplicativo e, em seguida, deixaremos os valores padrão. Em seguida, você pode configurar quais atributos de usuário cada aplicativo pode ler e gravar.

Etapa 8 na criação do grupo de usuários
Configurando aplicativos cliente para o grupo de usuários (Ver versão grande)

Você pode definir os valores que desejar nesta etapa, desde que o endereço de e-mail, sobrenome e nome próprio sejam legíveis e graváveis ​​pelo aplicativo. Certifique-se de clicar na opção “Create App Client” antes de continuar.

9. Gatilhos

Com os gatilhos, você pode usar as funções do Lambda para personalizar completamente o processo do ciclo de vida do usuário. Por exemplo, se você deseja que apenas usuários com um endereço de e-mail do domínio da sua empresa possam se inscrever, você pode adicionar uma função Lambda para o gatilho "Pré-inscrição" para realizar essa validação e rejeitar qualquer solicitação de inscrição que não passa.

Para nosso aplicativo de demonstração, não adicionarei nenhum gatilho.

Etapa 9 na criação do grupo de usuários
Configurando acionadores para o grupo de usuários (Ver versão grande)

10. Revisão

Percebo que isso pode ter parecido um processo demorado e árduo. Mas lembre-se de que cada etapa na criação de um grupo de usuários tem flexibilidade que permite que a solução se ajuste a mais casos de uso. E agora para a notícia que você estava esperando para ouvir: Este é o último passo.

Apenas revise as configurações para certificar-se de que você as configurou corretamente para o aplicativo de demonstração. A partir desta tela, você pode voltar e editar qualquer uma das configurações anteriores. Depois que o grupo de usuários é criado, alguns valores de configuração (como atributos obrigatórios) não podem ser alterados.

Com seu novo grupo de usuários criado, agora você pode prosseguir para integrá-los em um aplicativo iOS de amostra usando o AWS SDK para iOS.

Etapa 10 na criação do grupo de usuários
Revisão final do grupo de usuários antes da criação (Ver versão grande)

Configurando seu aplicativo iOS para seu grupo de usuários

Eu criei um aplicativo iOS de exemplo que se integra ao Cognito para permitir que o usuário faça login, saia, digite seu nome e sobrenome e defina uma senha. Para esta demonstração inicial, a inscrição do usuário não está incluída, então usei o console do Cognito para adicionar um novo usuário para teste.

O código para este aplicativo pode ser encontrado no meu repositório GitHub.

Configurando dependências

Este aplicativo usa CocoaPods para gerenciar dependências. Neste ponto, as únicas dependências são as partes específicas do AWS iOS SDK relacionadas aos grupos de usuários do Cognito.

(Uma descrição completa do CocoaPods está além do escopo deste artigo, no entanto, um recurso no site do CocoaPods o ajudará a começar a trabalhar, caso esse conceito seja novo para você.)

O conteúdo do Podfile para esta aplicação pode ser visto abaixo:

 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

Supondo que o CocoaPods esteja instalado em sua máquina, basta executar o pod install e as dependências necessárias serão instaladas para você.

Configuração do grupo de usuários

A próxima etapa é incluir os valores para seu grupo de usuários e aplicativo cliente. O aplicativo de demonstração está configurado para usar um arquivo, CognitoApplication/CognitoConfig.plist , do qual extrair essas informações. Quatro valores precisam ser definidos:

  • region (cadeia)
    Esta é a região na qual você criou seu grupo de usuários. Ele precisa ser o identificador de região padrão, como us-east-1 ou ap-southeast-1 .
  • poolId (string)
    Este é o ID do grupo de usuários que você criou.
  • clientId (cadeia de caracteres)
    Este é o clientId configurado como parte do aplicativo que você anexou ao grupo de usuários.
  • clientSecret (string)
    Este é o clientSecret que está configurado como parte do aplicativo que você anexou ao grupo de usuários.

Com esse arquivo e os valores apropriados, o aplicativo de demonstração pode ser iniciado. Se ocorrer alguma exceção durante a inicialização, certifique-se de ter incluído cada um dos quatro valores mostrados abaixo e de que o arquivo seja colocado no diretório correto.

Configuração de plist no Xcode
Configuração do grupo de usuários no Xcode com o arquivo plist (Ver versão grande)

Integração de delegados de aplicativos

O núcleo da integração com o Amazon Cognito acontece dentro do AppDelegate do aplicativo. Nosso primeiro passo é garantir que configuramos o log e nos conectamos ao nosso grupo de usuários. Como parte desse processo, designaremos nosso AppDelegate como o delegado do grupo de usuários. Para este exemplo básico, podemos manter essa lógica dentro do AppDelegate . Para projetos maiores, pode fazer sentido lidar com isso em outro lugar.

 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 }

Depois que essa configuração estiver em vigor, precisamos configurar os métodos delegados para o grupo de usuários. O protocolo que estamos implementando é AWSCognitoIdentityInteractiveAuthenticationDelegate . Esse delegado será chamado sempre que o usuário precisar fazer login, redefinir sua senha ou fornecer um código de autenticação multifator ou se precisarmos perguntar ao usuário se ele deseja que seu dispositivo seja lembrado. Para nosso exemplo, precisamos apenas implementar os métodos startPasswordAuthentication e 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! } }

Uma coisa importante a ser observada é que esses dois métodos retornam um controlador de exibição que implementa um protocolo específico. Por exemplo, o LoginViewController implementa AWSCognitoIdentityPasswordAuthentication , que tem um único método que é chamado com os parâmetros necessários para permitir que o usuário conclua o processo de login.

Fluxo de autenticação

Com todas essas peças no aplicativo de demonstração, agora você pode ver o processo de login funcionar do começo ao fim. A visualização principal do aplicativo mostra o nome de usuário e o nome e sobrenome do usuário. Para que isso aconteça, as seguintes etapas ocorrem:

  1. No AppViewController , chamamos o método fetchUserAttributes no método viewDidLoad . Se o usuário não estiver logado, isso acionará o processo de login.
  2. O método startPasswordAuthentication no AppDelegate será acionado. Este método carrega o LoginViewController e o apresenta.
  3. O método getDetails de LoginViewController é chamado pelo AWS SDK. Isso inclui um objeto que é uma instância de AWSTaskCompletionSource , que podemos usar para permitir que o usuário tente fazer login.
  4. Quando o usuário pressiona o botão “Log in”, passamos as credenciais de login para esse objeto. Isso chamará o método didCompleteStepWithError e podemos manipular o resultado de acordo. Se não houver erro, podemos dispensar o controlador de visualização.
  5. Se criamos o usuário no console, teremos outra etapa para tratar aqui. Como demos ao usuário uma senha temporária, ele precisará definir uma mais permanente. Além disso, como definimos o nome e o nome da família como parâmetros obrigatórios, precisamos permitir que o usuário os insira também. O AWS SDK detectará isso e chamará o método startNewPasswordRequired no AppDelegate . Isso apresentará o ResetPasswordViewController e definirá sua instância de AWSTaskCompletionSource .
  6. O ResetPasswordViewController funciona quase de forma idêntica ao LoginViewController . Nós simplesmente precisamos pedir ao usuário os valores corretos e então enviar esses valores. Depois que esse processo for concluído com êxito, descartamos o controlador de exibição.
  7. Depois que todo o processo de login for concluído, o SDK armazenará com segurança os tokens retornados pelo Cognito. Então, finalmente recuperaremos os detalhes do usuário e podemos usá-los para preencher o AppViewController com o nome de usuário, nome e sobrenome do usuário.

O aplicativo de trabalho com autenticação funcionando
O aplicativo de exemplo funcional, mostrando o nome de usuário e os metadados

Conclusão

Embora o processo de configuração do grupo de usuários possa ter várias etapas, essas etapas são fáceis de navegar. Além disso, a quantidade de configuração possível deve dar a você a confiança de que ela pode suportar a maioria dos casos de uso. Em meu trabalho diário na Universal Mind, trabalhei com vários clientes que estão migrando seus aplicativos existentes para aproveitar os recursos que o Cognito oferece para gerenciamento de usuários.

Independentemente de você precisar implementar um sistema de gerenciamento de usuários regularmente, essa é uma ferramenta que todo desenvolvedor móvel e web deve ter em sua caixa de ferramentas . No próximo artigo desta série, começaremos a explorar um pouco mais os recursos do Cognito, implementando um aplicativo de demonstração mais completo que implementa mais casos de uso comuns de gerenciamento de usuários.

Com um pouco de prática, você pode impressionar todos os seus amigos configurando um novo aplicativo que satisfaça todos esses casos de uso de gerenciamento de usuários em um dia. Isso é muito bom para um dia de trabalho.

Links e recursos

  • Amazon Cognito
  • “Recursos do desenvolvedor”, Amazon Cognito
  • SDK móvel da AWS
  • “Tutorial CocoaPods para Swift: Introdução”, Joshua Greene, raywenderlich.com