Autenticazione utente per app Web e iOS con AWS Cognito (Parte 1)
Pubblicato: 2022-03-10Nel corso degli anni ho costruito da zero almeno tre sistemi di gestione degli utenti. Gran parte dell'approccio può essere basato su una base standard, ma ci sono sempre alcuni elementi chiave che devono essere personalizzati per un particolare cliente. Questo è abbastanza preoccupante che un'intera categoria di servizi di gestione, autenticazione e autorizzazione degli utenti sia sorta per soddisfare questa esigenza. Servizi come Auth0 dispongono di intere soluzioni basate sulla gestione di utenti e identità con cui gli sviluppatori possono integrarsi.
Un servizio che fornisce questa funzionalità è Cognito di Amazon Web Services (AWS'). Cognito è uno strumento che consente agli utenti di registrarsi e accedere alle applicazioni Web e mobili create dall'utente. Oltre a questa funzionalità, consente anche la memorizzazione dei dati utente offline e fornisce la sincronizzazione di questi dati. Come afferma Amazon, "Con Amazon Cognito, puoi concentrarti sulla creazione di fantastiche esperienze con le app invece di preoccuparti di creare, proteggere e ridimensionare una soluzione per gestire la gestione degli utenti, l'autenticazione e la sincronizzazione su tutti i dispositivi".
Sottovalutando i caroselli
I caroselli non meritano davvero la cattiva reputazione che hanno guadagnato nel corso degli anni. Possono rivelarsi molto efficaci e sono disponibili in molte forme e dimensioni. Leggi un articolo correlato →
L'anno scorso, Amazon ha introdotto un'aggiunta al suo servizio Cognito, pool di utenti personalizzati. Questa funzionalità ora fornisce ciò di cui io e altri sviluppatori abbiamo bisogno per avere un sistema di gestione degli utenti completo, personalizzabile e multipiattaforma, con la flessibilità necessaria per adattarsi alla maggior parte dei casi d'uso. Per capire perché, dobbiamo dare una rapida occhiata a cos'è la gestione degli utenti e quali problemi risolve.

In questo articolo, passeremo la maggior parte del nostro tempo a esaminare il processo di configurazione di un pool di utenti per le nostre esigenze. Quindi, integreremo questo pool di utenti con un'applicazione iOS e consentiremo a un utente di accedere e recuperare gli attributi associati al proprio account utente. Alla fine, avremo un'applicazione demo limitata, ma che gestisce il nucleo della gestione degli utenti. Inoltre, dopo che questo sarà a posto, ci sarà un articolo di follow-up che approfondirà la questione.
Di cosa abbiamo bisogno dalla gestione degli utenti?
Se hai un'app mobile o web, di cosa hai bisogno esattamente in termini di gestione degli utenti? Sebbene il login dell'utente sia probabilmente la prima cosa a cui penseresti, non possiamo fermarci qui. Se desideriamo un sistema di gestione degli utenti flessibile che funzioni per la maggior parte dei casi d'uso di app Web e mobili, dovrebbe avere le seguenti funzionalità:
- login con nome utente e password;
- hashing e archiviazione sicuri delle password;
- modifiche della password;
- politica e convalida delle password;
- trigger del ciclo di vita dell'utente (e-mail di benvenuto, e-mail di addio, ecc.);
- attributi utente (nome, cognome, ecc.);
- configurazione richiesta e attributi opzionali per utente;
- gestione delle password dimenticate;
- convalida del numero di telefono tramite SMS;
- verifica email;
- Accesso API agli endpoint in base alle autorizzazioni;
- archiviazione sicura di token di accesso su dispositivi mobili;
- archiviazione offline di attributi utente per dispositivi mobili;
- sincronizzazione degli attributi utente per gli stati online e offline;
- autenticazione a più fattori.
Sebbene la gestione degli utenti possa inizialmente sembrare un sistema di accesso, la funzionalità deve andare ben oltre affinché il sistema sia veramente sufficientemente flessibile da gestire la maggior parte dei casi d'uso. Questo chiaramente va ben oltre un semplice nome utente e password.
Qui è necessario richiamare un elemento aggiuntivo: la sicurezza. Uno dei requisiti di qualsiasi sistema di gestione degli utenti è che deve essere continuamente valutato per la sicurezza del sistema nel suo insieme. Molti sistemi di gestione utente personalizzati presentano vulnerabilità che semplicemente non sono state corrette. Nell'ultimo anno si sono verificate violazioni della sicurezza dei sistemi di gestione degli utenti di aziende come Dropbox, Dailymotion, Twitter e Yahoo. Se scegli di creare una soluzione personalizzata, sei pronto per proteggere il tuo sistema.
Inserisci Amazon Cognito
Amazon Cognito è un servizio gestito che ti consente di integrare un sistema di gestione degli utenti flessibile e scalabile nelle tue applicazioni web e mobili. Cognito offre due modi distinti per utilizzare il servizio: identità federate, che consentono l'accesso tramite social network come Facebook, e pool di utenti, che offrono funzionalità di gestione degli utenti completamente personalizzate per un'app o una suite di applicazioni specifica.
Le identità federate sono ottime se vuoi che gli utenti possano accedere con Facebook (o Google, Amazon, ecc.), ma ciò significa che una parte del processo di gestione degli utenti sarà stata esternalizzata a Facebook. Sebbene ciò possa essere accettabile in alcuni casi, gli utenti potrebbero non voler collegare il proprio account Facebook alla tua applicazione. Inoltre, potresti voler gestire direttamente più ciclo di vita dell'utente e, per questo, le identità federate non sono così flessibili. Ai fini dell'articolo di oggi, ci concentreremo sui pool di utenti perché forniscono la flessibilità necessaria per una solida piattaforma di gestione degli utenti che si adatta alla maggior parte dei casi d'uso. In questo modo, avrai un approccio che può essere utilizzato nella maggior parte dei progetti.
Poiché si tratta di un servizio AWS, ci sono altri vantaggi nell'utilizzo di Cognito. Cognito può integrarsi con API Gateway per fornire un modo indolore per autorizzare l'accesso all'API in base ai token restituiti da un login Cognito. Inoltre, se stai già sfruttando altri servizi AWS per la tua applicazione mobile, puoi utilizzare il tuo pool di utenti come provider di identità per le tue credenziali AWS.
Come con qualsiasi altro servizio AWS, è previsto un costo. Il prezzo di Cognito si basa sugli utenti attivi mensili (MAU). La grande notizia per la maggior parte degli sviluppatori è che esiste un livello gratuito indefinito con un limite di 50.000 MAU quando si utilizza un pool di utenti personalizzato. Se hai un'applicazione di grandi dimensioni, questo ti darà un gran numero di utenti per pilotare un nuovo approccio alla gestione degli utenti. Tuttavia, sospetto che molti di voi abbiano esperienze che non andranno mai oltre i 50.000 utenti. In questo caso, la gestione degli utenti principali sarà praticamente gratuita. L'unica eccezione sono altri servizi AWS che utilizzerai come parte del processo di gestione degli utenti, come Lambda, SNS e S3.
Creazione di un pool di utenti
Il primo passaggio per integrare un pool di utenti nell'applicazione mobile consiste nel creare un pool di utenti Cognito. Questo ci darà i valori di configurazione necessari per collegarci alla nostra applicazione di esempio. Per creare un nuovo pool di utenti, segui la procedura guidata fornita nella console Cognito di Amazon.
Esaminiamo il processo di creazione di un pool di utenti. Devo avvertirti che questo è un processo lungo. In molti modi, questa è una buona cosa perché mostra aree di flessibilità. Tuttavia, ti consigliamo di prendere una tazza di caffè e allacciarti la cintura per questo.
1. Nome
Il passaggio iniziale nella creazione di un pool di utenti prevede l'impostazione di un nome per il pool di utenti e la selezione dell'approccio da adottare per creare il pool di utenti. Puoi rivedere le impostazioni predefinite o "passare attraverso" le impostazioni. Poiché vogliamo avere una buona conoscenza pratica di come viene configurato il pool di utenti, scegli l'opzione "Passa attraverso le impostazioni".

2. Attributi
La configurazione degli attributi richiederà un po' di riflessione. Per ogni pool di utenti, sarà necessario determinare quali attributi verranno archiviati nel sistema e quali sono obbligatori. Poiché il sistema applicherà i valori richiesti, non è possibile modificarli in futuro. L'approccio migliore qui è contrassegnare qui solo i valori veramente essenziali come richiesto. Inoltre, se desideri che gli utenti possano accedere con il loro indirizzo e-mail, assicurati di contrassegnarlo come alias.
Se desideri includere valori personalizzati, dovrai farlo anche qui. Ogni valore personalizzato avrà un tipo, regole di convalida facoltative e un'opzione per essere mutabile (modificabile) o non mutabile (non modificabile). C'è un limite fisso di 25 attributi personalizzati.
Infine, è necessario fare un punto qui sui nomi utente. Il valore del nome utente per ogni utente è immutabile (non modificabile). Ciò significa che, nella maggior parte dei casi, avrebbe senso rendere questo valore generato automaticamente. Questo è il motivo per cui esiste il valore "nome utente preferito". Se desideri che gli utenti dispongano di un valore per il nome utente che possono modificare, contrassegna semplicemente l'attributo "nome utente preferito" come alias. Se desideri che gli utenti accedano semplicemente con il loro indirizzo email, assicurati di contrassegnare l'attributo "email" sia come richiesto che come alias.
Per la nostra applicazione demo, ho scelto di rendere obbligatori "e-mail", "nome di battesimo" e "cognome".

3. Politiche
Dopo aver configurato gli attributi, sarai in grado di configurare le politiche per l'account. Il primo criterio da configurare è il criterio password. Il criterio consente di configurare sia la lunghezza sia se si richiedono numeri, caratteri speciali, lettere maiuscole o minuscole. Questo criterio verrà applicato sia alle password che gli utenti immettono sia alle password che gli amministratori assegnano agli utenti.
Le politiche successive riguardano la registrazione degli utenti. Per un'applicazione pubblica, probabilmente vorrai consentire agli utenti di registrarsi da soli. Tuttavia, a seconda del tipo di applicazione, potresti voler limitare la registrazione e fare in modo che il sistema sia solo su invito. Inoltre, dovrai configurare la velocità di scadenza di questi inviti se non vengono utilizzati.
Per la nostra applicazione demo, ho scelto di utilizzare solo i valori predefiniti, con l'eccezione che non voglio che gli utenti possano registrarsi da soli. Con questi valori in atto, possiamo procedere alle verifiche.

4. Verifiche
Il passaggio delle verifiche consente di impostare l'autenticazione a più fattori, nonché la verifica tramite e-mail e telefono. Sebbene questa funzionalità sia relativamente facile da configurare nella console, tieni presente che dovrai richiedere un aumento della spesa per AWS SNS se desideri verificare i numeri di telefono o utilizzare l'autenticazione a più fattori.
Per la nostra applicazione demo, ho scelto di utilizzare solo i valori predefiniti.

5. Personalizzazioni dei messaggi
Questo passaggio ti consente di personalizzare l'e-mail e i messaggi SMS che il tuo pool di utenti invierà, nonché gli indirizzi e-mail "da" e "rispondi a". Ai fini della nostra applicazione demo, lascerò qui i valori predefiniti e procederò.

6. Tag
Se non conosci AWS, potresti non aver bisogno di specificare alcun tag. Tuttavia, nel caso in cui la tua organizzazione utilizzi AWS regolarmente, i tag forniscono un modo per analizzare la spesa e assegnare autorizzazioni con IAM. Ad esempio, alcune organizzazioni specificano i tag per ambiente (sviluppo, gestione temporanea, produzione) e per progetto.
Indipendentemente da ciò che inserisci in questo passaggio, non influirà sulla nostra applicazione demo.

7. Dispositivi
Il passaggio successivo consente di definire se il pool di utenti ricorderà i dispositivi dell'utente. Questo è un passaggio di sicurezza aggiuntivo che ti consente di vedere su quali dispositivi è stato effettuato l'accesso a un account specifico. Questo ha un valore extra quando si sfrutta l'autenticazione a più fattori (MFA). Se il dispositivo viene ricordato, puoi scegliere di non richiedere un token MFA ad ogni accesso.

Ai fini dell'applicazione demo, ho scelto di impostare il valore su "Sempre".

8. Client di app
Per ogni applicazione per la quale si desidera utilizzare il pool di utenti (ad esempio un'applicazione iOS, un'applicazione Web, un'applicazione Android, ecc.), è necessario creare un'app. Tuttavia, puoi tornare indietro e crearli dopo che il pool di utenti è stato creato, quindi non è ancora necessario aggiungerli tutti.
Ogni applicazione ha diversi valori che puoi configurare. Per questa applicazione demo, assegneremo un nome all'app e poi lasceremo i valori predefiniti. Successivamente, puoi configurare quali attributi utente può leggere e scrivere ogni app.

Puoi impostare i valori che preferisci in questo passaggio, purché l'indirizzo e-mail, il cognome e il nome siano tutti leggibili e scrivibili dall'applicazione. Assicurati di fare clic sull'opzione "Crea client app" prima di procedere.
9. Trigger
Con i trigger, puoi utilizzare le funzioni Lambda per personalizzare completamente il processo del ciclo di vita dell'utente. Ad esempio, se desideri che solo gli utenti con un indirizzo email del dominio della tua azienda possano registrarsi, puoi aggiungere una funzione Lambda per il trigger "Pre-registrazione" per eseguire questa convalida e rifiutare qualsiasi richiesta di registrazione che non passa.
Per la nostra applicazione demo, non aggiungerò alcun trigger.

10. Revisione
Mi rendo conto che questo potrebbe sembrare un processo lungo e arduo. Ma tieni presente che ogni passaggio nella creazione di un pool di utenti ha una flessibilità che consente alla soluzione di adattarsi a più casi d'uso. E ora le notizie che stavate aspettando: questo è l'ultimo passaggio.
Rivedi le impostazioni per assicurarti di averle configurate correttamente per l'applicazione demo. Da questa schermata è possibile tornare indietro e modificare qualsiasi impostazione precedente. Una volta creato il pool di utenti, alcuni valori di configurazione (come gli attributi obbligatori) non possono essere modificati.
Con il tuo nuovo pool di utenti creato, puoi ora procedere all'integrazione in un'applicazione iOS di esempio utilizzando l'SDK AWS per iOS.

Configurazione della tua applicazione iOS per il tuo pool di utenti
Ho creato un'applicazione iOS di esempio che si integra con Cognito per consentire all'utente di accedere, disconnettersi, inserire nome e cognome e impostare una password. Per questa demo iniziale, la registrazione dell'utente non è inclusa, quindi ho utilizzato la console di Cognito per aggiungere un nuovo utente per il test.
Il codice per questa applicazione può essere trovato nel mio repository GitHub.
Configurazione delle dipendenze
Questa applicazione utilizza CocoaPods per la gestione delle dipendenze. A questo punto, le uniche dipendenze sono le parti specifiche dell'SDK AWS iOS che si riferiscono ai pool di utenti Cognito.
(Una descrizione completa di CocoaPods va oltre lo scopo di questo articolo, tuttavia, una risorsa sul sito Web di CocoaPods ti aiuterà a metterti in funzione, nel caso in cui questo concetto sia nuovo per te.)
Il contenuto del Podfile per questa applicazione può essere visto di seguito:
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
Supponendo che CocoaPods sia installato sulla tua macchina, puoi semplicemente eseguire pod install
e le dipendenze necessarie verranno installate per te.
Configurazione del pool di utenti
Il passaggio successivo consiste nell'includere i valori per il pool di utenti e l'applicazione client. L'applicazione demo è configurata per usare un file, CognitoApplication/CognitoConfig.plist
, da cui estrarre queste informazioni. È necessario definire quattro valori:
-
region
(stringa)
Questa è la regione in cui hai creato il tuo pool di utenti. Deve essere l'identificatore di regione standard, ad esempious-east-1
oap-southeast-1
. -
poolId
(stringa)
Questo è l'ID del pool di utenti che hai creato. -
clientId
(stringa)
Questo è ilclientId
configurato come parte dell'app collegata al pool di utenti. -
clientSecret
(stringa)
Questo è ilclientSecret
configurato come parte dell'app collegata al pool di utenti.
Con quel file e i valori corretti in atto, è possibile avviare l'applicazione demo. Se si verificano eccezioni durante l'avvio, assicurati di aver incluso ciascuno dei quattro valori mostrati di seguito e che il file sia posizionato nella directory corretta.

plist
(Visualizza versione grande)Integrazione del delegato dell'app
Il nucleo dell'integrazione con Amazon Cognito avviene all'interno di AppDelegate
dell'applicazione. Il nostro primo passo è assicurarci di aver impostato la registrazione e di essere connessi al nostro pool di utenti. Come parte di tale processo, assegneremo il nostro AppDelegate
come delegato del pool di utenti. Per questo esempio di base, possiamo mantenere questa logica all'interno di AppDelegate
. Per progetti più grandi, potrebbe avere senso gestirlo altrove.
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 }
Dopo aver eseguito questa configurazione, è necessario configurare i metodi delegati per il pool di utenti. Il protocollo che stiamo implementando è AWSCognitoIdentityInteractiveAuthenticationDelegate
. Questo delegato verrà chiamato ogni volta che l'utente ha bisogno di accedere, reimpostare la password o fornire un codice di autenticazione a più fattori o se è necessario interrogare l'utente se desidera che il proprio dispositivo venga ricordato. Per il nostro esempio, dobbiamo solo implementare i metodi 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! } }
Una cosa fondamentale da notare è che entrambi questi metodi restituiscono un controller di visualizzazione che implementa un protocollo specifico. Ad esempio, LoginViewController
implementa AWSCognitoIdentityPasswordAuthentication
, che dispone di un unico metodo che viene chiamato con i parametri necessari per consentire all'utente di completare il processo di accesso.
Flusso di autenticazione
Con tutti questi elementi in atto nell'applicazione demo, ora puoi vedere il processo di accesso dall'inizio alla fine. La vista principale dell'applicazione mostra il nome utente e il nome e cognome dell'utente. Affinché ciò avvenga, si verificano i seguenti passaggi:
- In
AppViewController
chiamiamo il metodofetchUserAttributes
nel metodoviewDidLoad
. Se l'utente non ha effettuato l'accesso, questo attiverà il processo di accesso. - Verrà attivato il metodo
startPasswordAuthentication
inAppDelegate
. Questo metodo caricaLoginViewController
e lo presenta. - Il metodo
getDetails
diLoginViewController
viene chiamato dall'SDK AWS. Ciò include un oggetto che è un'istanza diAWSTaskCompletionSource
, che possiamo utilizzare per consentire all'utente di tentare di accedere. - Quando l'utente preme il pulsante "Accedi", passiamo le credenziali di accesso a quell'oggetto. Questo chiamerà quindi il metodo
didCompleteStepWithError
e possiamo gestire il risultato di conseguenza. Se non ci sono errori, possiamo ignorare il controller di visualizzazione. - Se abbiamo creato l'utente nella console, avremo un altro passaggio da gestire qui. Poiché abbiamo fornito all'utente una password temporanea, sarà necessario impostarne una più permanente. Inoltre, poiché impostiamo il nome e il cognome come parametri obbligatori, dobbiamo consentire all'utente di inserirli anche. L'SDK AWS lo rileverà e chiamerà il metodo
startNewPasswordRequired
inAppDelegate
. Questo presenteràResetPasswordViewController
e imposterà la sua istanza diAWSTaskCompletionSource
. -
ResetPasswordViewController
funziona in modo quasi identico aLoginViewController
. Dobbiamo semplicemente chiedere all'utente i valori corretti e quindi inviare tali valori. Una volta che questo processo è stato completato con successo, chiudiamo il controller di visualizzazione. - Una volta completato l'intero processo di accesso, l'SDK memorizzerà in modo sicuro i token restituiti da Cognito. Quindi, recupereremo finalmente i dettagli dell'utente e potremo utilizzarli per popolare
AppViewController
con il nome utente, il nome e il cognome dell'utente.

Conclusione
Sebbene il processo di configurazione del pool di utenti possa avere diversi passaggi, questi passaggi sono facili da navigare. Inoltre, la quantità di configurazione possibile dovrebbe darti la certezza che può supportare la maggior parte dei casi d'uso. Nel mio lavoro quotidiano presso Universal Mind, ho lavorato con diversi clienti che stanno spostando le loro applicazioni esistenti per sfruttare le capacità che Cognito fornisce per la gestione degli utenti.
Indipendentemente dal fatto che sia necessario implementare regolarmente un sistema di gestione degli utenti, questo è uno strumento che ogni sviluppatore mobile e web dovrebbe avere nella propria cassetta degli attrezzi . Nel prossimo articolo di questa serie, inizieremo a esplorare un po' di più le funzionalità di Cognito implementando un'applicazione demo più completa che implementa più casi d'uso comuni di gestione degli utenti.
Con un po' di pratica, puoi impressionare tutti i tuoi amici configurando una nuova applicazione che soddisfi tutti questi casi d'uso di gestione degli utenti in un giorno. Va abbastanza bene per una giornata di lavoro.
Collegamenti e risorse
- Amazon Cognito
- "Risorse per gli sviluppatori", Amazon Cognito
- SDK per dispositivi mobili AWS
- "CocoaPods Tutorial per Swift: Guida introduttiva", Joshua Greene, raywenderlich.com