Nozioni di base su AWS

Creazione di un'applicazione Android

Creazione di un'applicazione Android semplice utilizzando AWS Amplify

Modulo 3: Aggiunta di un'autenticazione

In questo modulo verrà utilizzata l'interfaccia a riga di comando (CLI) di Amplify per configurare e aggiungere un'autenticazione alla tua app.

Introduzione

La prossima funzionalità che verrà aggiunta sarà l'autenticazione dell'utente. In questo modulo imparerai come autenticare un utente con l'interfaccia a riga di comando (CLI) e le librerie di Amplify sfruttando Amazon Cognito, un provider di identità utente gestito.

Imparerai anche come usare l'interfaccia utente in hosting di Cognito per presentare un intero flusso di autenticazione dell'utente, consentendo agli utenti di registrarsi, accedere e ripristinare la password con poche righe di codice.

L'utilizzo di una "interfaccia utente in hosting" significa che l'applicazione sfrutta le pagine Web Cognito per i flussi dell'interfaccia utente di accesso e registrazione. L'utente dell'applicazione viene reindirizzato a una pagina Web ospitata da Cognito e reindirizzato nuovamente all'applicazione dopo l'accesso. Ovviamente, Cognito e Amplify supportano anche l'interfaccia utente nativa, segui le istruzioni di questo workshop per ulteriori informazioni sull'interfaccia utente di autenticazione personalizzata.

Avrai modo di approfondire i seguenti aspetti

  • Creazione e distribuzione di un servizio di autenticazione
  • Configurazione dell'applicazione Android per includere l'autenticazione dell'interfaccia utente in hosting Cognito

Concetti chiave

Librerie Amplify: le librerie di Amplify consentono di interagire con i servizi AWS da un'applicazione Web o mobile.

Autenticazione: nei software l'autenticazione è il processo di verifica e gestione dell'identità di un utente usando un servizio di autenticazione o API.

 Tempo richiesto per il completamento

10 minuti

 Servizi utilizzati

Implementazione

  • Creazione del servizio di autenticazione

    Per creare il servizio di autenticazione, apri un terminale ed esegui questo comando:

    amplify add auth
    
    ? Do you want to use the default authentication and security configuration? Select Default configuration with Social Provider and press enter
    ? How do you want users to be able to sign in? Select the default Username and press enter
    ? Do you want to configure advanced settings? Select the default No, I am done and press enter
    ? What domain name prefix do you want to use? Select the default and press enter
    Enter your redirect signin URI: type gettingstarted:// and press enter
    ? Do you want to add another redirect signin URI? Select the default N and press enter
    Enter your redirect signout URI: type gettingstarted:// and press enter
    ? Do you want to add another redirect signout URI? Select the default N and press enter
    ? Select the social providers you want to configure for your user pool: do not select any provider and press enter

    Saprai che la configurazione è andata a buon fine quando vedrai questo messaggio (il nome esatto della risorsa sarà diverso):

    Successfully added resource androidgettingstartedfc5a4717 locally
  • Distribuzione del servizio di autenticazione

    Ora che il servizio di autenticazione è stato configurato localmente, può essere distribuito nel cloud. In un terminale, esegui questo comando nella directory del progetto:

    amplify push
    
    # press Y when asked to continue

    Dopo qualche istante, dovrebbe essere visualizzato il seguente messaggio:

    ✔ All resources are updated in the cloud
    
    Hosted UI Endpoint: https://androidgettingstarted-dev.auth.eu-central-1.amazoncognito.com/
    Test Your Hosted UI Endpoint: https://androidgettingstarted-dev.auth.eu-central-1.amazoncognito.com/login?response_type=code&client_id=1234567890&redirect_uri=gettingstarted://
  • Aggiunta della libreria delle autenticazioni Amplify al progetto

    Prima di passare al codice, torna in Android Studio e aggiungi la seguente dipendenza al file build.gradle del modulo, insieme alle altre implementazioni 'amplifyframework' aggiunte in precedenza e fai clic su Sync Now (Sincronizza ora) quando richiesto:

    dependencies {
        ...
        // Amplify core dependency
        implementation 'com.amplifyframework:core:1.4.0'
        implementation 'com.amplifyframework:aws-auth-cognito:1.4.0'
    }
  • Configurazione della libreria delle autenticazioni Amplify in runtime

    Torna in Android Studio e apri il file Backend.kt. Nella classe Backend, aggiungi una riga al codice di inizializzazione Amplify aggiunto nella sezione precedente (nel metodo initialize()).

    Il blocco di codice completo dovrebbe avere il seguente aspetto:

    // inside Backend class
    fun initialize(applicationContext: Context) : Backend {
        try {
            Amplify.addPlugin(AWSCognitoAuthPlugin())
            Amplify.configure(applicationContext)
    
            Log.i(TAG, "Initialized Amplify")
        } catch (e: AmplifyException) {
            Log.e(TAG, "Could not initialize Amplify", e)
        }
        return this
    }

    Non dimenticare di aggiungere le istruzioni di importazione che Android Studio genera automaticamente (in Mac, fai clic su Alt + Invio per ciascun errore rilevato dall'editor di codice).

    Come nel passaggio precedente, aggiungi le istruzioni di importazione obbligatorie per ogni definizione di classe mancante (Alt + Invio sulle parole in rosso).

    Per verificare che tutto funzioni come previsto, crea il progetto. Fai clic sul menu Build (Crea) e seleziona Make Project (Crea progetto) oppure, nei Mac, digita ⌘F9. Non dovrebbero essere restituiti errori.

  • Avvio dell'autenticazione in runtime

    La modifica al codice restante traccia lo stato di un utente (ha eseguito l'accesso oppure no?) e avvia l'interfaccia utente di accesso o registrazione quando un utente seleziona l'icona del lucchetto.

    a. Aggiunta dei metodi signIn e signOut
    Aggiungi i seguenti quattro metodi in un punto qualsiasi della classe di back-end:
    private fun updateUserData(withSignedInStatus : Boolean) {
        UserData.setSignedIn(withSignedInStatus)
    }
    
    fun signOut() {
        Log.i(TAG, "Initiate Signout Sequence")
    
        Amplify.Auth.signOut(
            { Log.i(TAG, "Signed out!") },
            { error -> Log.e(TAG, error.toString()) }
        )
    }
    
    fun signIn(callingActivity: Activity) {
        Log.i(TAG, "Initiate Signin Sequence")
    
        Amplify.Auth.signInWithWebUI(
            callingActivity,
            { result: AuthSignInResult ->  Log.i(TAG, result.toString()) },
            { error: AuthException -> Log.e(TAG, error.toString()) }
        )
    }

    Quindi, aggiungi le istruzioni di importazione obbligatorie per ogni definizione di classe mancante (Alt + Invio sulle parole in rosso). Quando puoi scegliere tra più classi, assicurati di selezionare quella del pacchetto Amplify, così come mostrato nella schermata seguente.

    AndroidAppTutorial_Modiule3_Image1

    Nota che non aggiorniamo il contrassegno UserData.isSignedIn di questi metodi; questa operazione verrà eseguita nella sezione successiva.

    b. Aggiunta di un listener dell'hub di autenticazione

    Per tenere traccia delle modifiche dello stato di autenticazione, aggiungiamo il codice per effettuare l'iscrizione agli eventi di autenticazione inviati da Amplify. Inizializziamo l'hub nel metodo Backend.initialize().

    Quando si riceve un evento di autenticazione, chiamiamo il metodo updateUserData(). Questo metodo mantiene sincronizzato l'oggetto UserData. La proprietà UserData.isSignedIn è un valore LiveData<Boolean>, il che significa che gli osservatori che effettuano l'iscrizione a questa proprietà riceveranno una notifica al variare del valore. Utilizziamo questo meccanismo per aggiornare automaticamente l'interfaccia utente. Puoi scoprire di più sui LiveData nella documentazione Android.

    Inoltre, aggiungiamo il codice per controllare lo stato di autenticazione precedente al momento dell'avvio dell'applicazione. All'avvio dell'applicazione, controlla se esista già una sessione Cognito e aggiorna gli UserData di conseguenza.

    In Backend.initialize(), aggiungi il seguente codice dopo il blocco try/catch e prima dell'istruzione di ritorno.

    // in Backend.initialize() function, after the try/catch block but before the return statement 
    
    Log.i(TAG, "registering hub event")
    
    // listen to auth event
    Amplify.Hub.subscribe(HubChannel.AUTH) { hubEvent: HubEvent<*> ->
    
        when (hubEvent.name) {
            InitializationStatus.SUCCEEDED.toString() -> {
                Log.i(TAG, "Amplify successfully initialized")
            }
            InitializationStatus.FAILED.toString() -> {
                Log.i(TAG, "Amplify initialization failed")
            }
            else -> {
                when (AuthChannelEventName.valueOf(hubEvent.name)) {
                    AuthChannelEventName.SIGNED_IN -> {
                        updateUserData(true)
                        Log.i(TAG, "HUB : SIGNED_IN")
                    }
                    AuthChannelEventName.SIGNED_OUT -> {
                        updateUserData(false)
                        Log.i(TAG, "HUB : SIGNED_OUT")
                    }
                    else -> Log.i(TAG, """HUB EVENT:${hubEvent.name}""")
                }
            }
        }
    }
    
    Log.i(TAG, "retrieving session status")
    
    // is user already authenticated (from a previous execution) ?
    Amplify.Auth.fetchAuthSession(
        { result ->
            Log.i(TAG, result.toString())
            val cognitoAuthSession = result as AWSCognitoAuthSession
            // update UI
            this.updateUserData(cognitoAuthSession.isSignedIn)
            when (cognitoAuthSession.identityId.type) {
                AuthSessionResult.Type.SUCCESS ->  Log.i(TAG, "IdentityId: " + cognitoAuthSession.identityId.value)
                AuthSessionResult.Type.FAILURE -> Log.i(TAG, "IdentityId not present because: " + cognitoAuthSession.identityId.error.toString())
            }
        },
        { error -> Log.i(TAG, error.toString()) }
    )

    Per verificare che tutto funzioni come previsto, crea il progetto. Fai clic sul menu Build (Crea) e seleziona Make Project (Crea progetto) oppure, nei Mac, digita ⌘F9. Non dovrebbero essere restituiti errori.

    c. Aggiornamento del codice dell'interfaccia utente

    L'ultima modifica del codice è relativa all'interfaccia utente: aggiungiamo un FloatingActionButton all'attività principale.

    In res/layout, apri il file activity_main.xml e sostituisci il FloatingActionButton esistente con questo:

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fabAuth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_baseline_lock"
        app:fabCustomSize="60dp"
        app:fabSize="auto"
        />

    Aggiungi un'icona lucchetto sotto res/drawable. Fai clic con il tasto destro del mouse su drawable, seleziona New (Nuovo), quindi Vector Asset (Asset vettore). Scegli l'icona del lucchetto da Clip Art e inserisci il nome ic_baseline_lock (senza _24) quindi seleziona l'icona del lucchetto chiuso da Clip Art. Fai clic su Next (Avanti), quindi su Finish (Fine).

    Ripeti la stessa operazione con l'icona del lucchetto aperto.

    AndroidAppTutorial_Modiule3_Image2
    AndroidAppTutorial_Modiule3_Image3

    Al termine, dovresti avere i seguenti file nella directory drawable:

    AndroidAppTutorial_Modiule3_Image4

    Ora, collega il pulsante appena creato nel codice. In java/com.example.androidgettingstarted/, apri MainActivity.kt e aggiungi il codice seguente.

    // anywhere in the MainActivity class
    private fun setupAuthButton(userData: UserData) {
    
        // register a click listener
        fabAuth.setOnClickListener { view ->
    
            val authButton = view as FloatingActionButton
    
            if (userData.isSignedIn.value!!) {
                authButton.setImageResource(R.drawable.ic_baseline_lock_open)
                Backend.signOut()
            } else {
                authButton.setImageResource(R.drawable.ic_baseline_lock_open)
                Backend.signIn(this)
            }
        }
    }

    Sempre in MainActivity, aggiungi il seguente codice alla fine del metodo onCreate():

    setupAuthButton(UserData)
    
    UserData.isSignedIn.observe(this, Observer<Boolean> { isSignedUp ->
        // update UI
        Log.i(TAG, "isSignedIn changed : $isSignedUp")
    
        if (isSignedUp) {
            fabAuth.setImageResource(R.drawable.ic_baseline_lock_open)
        } else {
            fabAuth.setImageResource(R.drawable.ic_baseline_lock)
        }
    })

    Il codice di cui sopra registra un osservatore nel valore Userdata.isSignedIn. La chiusura viene chiamata quando cambia il valore isSignedIn. Ora modifichiamo semplicemente l'icona lucchetto: aperta quando l'utente è autenticato e chiusa quando l'utente non ha sessioni.

    Per verificare che tutto funzioni come previsto, crea il progetto. Fai clic sul menu Build (Crea) e seleziona Make Project (Crea progetto) oppure, nei Mac, digita ⌘F9. Non dovrebbero essere restituiti errori.

    d. Aggiornamento di AndroidManifest.xml e MainActivity

    Infine, dobbiamo garantire che l'applicazione venga avviata al termine della sequenza di autenticazione Web fornita dall'interfaccia utente in hosting Cognito. Aggiungiamo una nuova attività nel file manifest. L'attività viene chiamata alla ricezione dello schema URI gettingstarted.

    In Android Studio, sotto manifests, apri AndroidManifest.xml e aggiungi la seguente attività all'interno dell'elemento dell'applicazione.

        <activity
    android:name="com.amazonaws.mobileconnectors.cognitoauth.activities.CustomTabsRedirectActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
    
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
    
                <data android:scheme="gettingstarted" />
            </intent-filter>
        </activity>
    

    In java/com.example.androidgettingstarted/, apri MainActivity.kt e aggiungi il codice seguente in un punto qualsiasi della classe.

    // MainActivity.kt
    // receive the web redirect after authentication
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Backend.handleWebUISignInResponse(requestCode, resultCode, data)
    }

    In java/com.example.androidgettingstarted/, apri Backend.kt e aggiungi il codice seguente in un punto qualsiasi della classe.

    // Backend.kt
    // pass the data from web redirect to Amplify libs 
    fun handleWebUISignInResponse(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "received requestCode : $requestCode and resultCode : $resultCode")
        if (requestCode == AWSCognitoAuthPlugin.WEB_UI_SIGN_IN_ACTIVITY_CODE) {
            Amplify.Auth.handleWebUISignInResponse(data)
        }
    }

    e. Creazione e test

    Per verificare che tutto funzioni come previsto, crea ed esegui il progetto. Fai clic sull'icona Run (Esegui) ▶️ nella barra degli strumenti o digita ^ R. Non dovrebbero essere restituiti errori. L'applicazione si avvia e nella parte in basso a destra della schermata è presente un pulsante mobile di lucchetto chiuso.

    Ecco il flusso completo di registrazione.

    AndroidAppTutorial_Modiule3_Image5
    AndroidAppTutorial_Modiule3_Image6
    AndroidAppTutorial_Modiule3_Image7
    AndroidAppTutorial_Modiule3_Image8
    AndroidAppTutorial_Modiule3_Image9

Conclusione

Hai appena aggiunto l'autenticazione utente alla tua app con poche righe di codice! Nel prossimo modulo aggiungeremo un'API alla tua app.

Questo modulo è stato utile?

Grazie
Facci sapere cosa ti è piaciuto.
Chiudi
Spiacenti di non esserti stati d'aiuto
C'è qualcosa di obsoleto, ambiguo o approssimativo? Aiutaci a migliorare questo tutorial con il tuo feedback.
Chiudi

Aggiunta di un'API GraphQL e di un database