Erste Schritte mit AWS

Erstellen einer Android-Anwendung

Erstellen einer einfachen Android-Anwendung mit AWS Amplify

Modul 3: Authentifizierung hinzufügen

In diesem Modul verwenden Sie die Amplify-CLI und -Bibliotheken zur Konfiguration und zum Hinzufügen von Authentifizierung zu Ihrer Anwendung.

Einführung

Die nächste Funktion, die Sie hinzufügen werden, ist die Benutzerauthentifizierung. In diesem Modul lernen Sie, wie Sie einen Benutzer mit der Amplify-CLI und -Bibliotheken authentifizieren und dabei Amazon Cognito, einen verwalteten Benutzeridentitätsservice, nutzen können.

Sie werden auch lernen, wie man die Cognito Hosted User Interface (also eine gehostete Benutzeroberfläche) verwendet, um einen kompletten Benutzer-Authentifizierungsfluss darzustellen, der es den Benutzern ermöglicht, sich mit nur wenigen Codezeilen anzumelden, sich anzumelden und ihr Passwort zurückzusetzen.

Die Verwendung einer "gehosteten Benutzeroberfläche" bedeutet, dass die Anwendung die Cognito-Webseiten für die Abläufe der Anmeldung und der Benutzeroberflächen-Anmeldung nutzt. Der Benutzer der App wird auf eine von Cognito gehostete Webseite umgeleitet und nach der Anmeldung wieder auf die App zurückgeleitet. Natürlich unterstützen Cognito und Amplify auch native UI und Sie können diesen Workshop-Anweisungen folgen, um mehr über die benutzerdefinierte Authentifizierungs-UI zu erfahren.

Lerninhalte

  • Erstellen und Bereitstellen eines Authentifizierungsdienstes
  • Konfigurieren Sie Ihre Android-Anwendung so, dass sie Cognito Hosted UI-Authentifizierung enthält

Wichtige Konzepte

Amplify-Bibliotheken – Die Amplify-Bibliotheken ermöglichen Ihnen die Interaktion mit AWS-Services über eine Web- oder mobile Anwendung.

Authentifizierung – In der Software ist Authentifizierung der Prozess der Verifizierung und Verwaltung der Identität eines Benutzers unter Verwendung eines Authentifizierungsdienstes oder einer API.

 Veranschlagte Zeit

10 Minuten

 Verwendete Services

Implementierung

  • Um den Authentifizierungs-Service zu erstellen, öffnen Sie ein Terminal und führen Sie diesen Befehl aus:

    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

    Sie werden wissen, dass die Konfiguration erfolgreich ist, wenn Sie diese Meldung sehen (der genaue Name der Ressource variiert):

    Successfully added resource androidgettingstartedfc5a4717 locally
  • Nun, da der Authentifizierungs-Service lokal konfiguriert wurde, können wir ihn in der Cloud bereitstellen. Führen Sie diesen Befehl in einem Terminal in Ihrem Projektverzeichnis aus:

    amplify push
    
    # press Y when asked to continue

    Nach einer Weile sollten Sie die folgende Meldung sehen:

    ✔ 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://
  • Bevor Sie zum Code gehen, gehen Sie zurück zu Android Studio, fügen Sie die folgende Abhängigkeit zur `build.gradle` Ihres Moduls zusammen mit anderen `Amplifyframework`-Implementierungen hinzu, die Sie zuvor hinzugefügt haben, und klicken Sie auf Jetzt synchronisieren, wenn Sie dazu aufgefordert werden:

    dependencies {
        ...
        // Amplify core dependency
        implementation 'com.amplifyframework:core:1.4.0'
        implementation 'com.amplifyframework:aws-auth-cognito:1.4.0'
    }
  • Zurück zu Android Studio, öffnen Sie die Datei "Backend.kt". Fügen Sie in der Backend-Klasse eine Zeile zum Amplify Backend Initialisierungscode hinzu, den wir im vorherigen Abschnitt (in der initialize()-Methode) hinzugefügt haben.

    Der vollständige Codeblock sollte wie folgt aussehen:

    // 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
    }

    Vergessen Sie nicht, die Import-Anweisungen hinzuzufügen, Android Studio erledigt das automatisch für Sie (auf Mac klicken Sie bei jedem vom Code-Editor erkannten Fehler auf Alt + Enter).

    Fügen Sie wie im vorherigen Schritt die erforderlichen Importaufstellungen für jede fehlende Klassendefinition hinzu (Alt+Eingabe bei roten Wörtern).

    Um zu überprüfen, ob alles wie erwartet funktioniert, erstellen Sie das Projekt. Klicken Sie auf das Menü Build und wählen Sie Projekt machen oder, auf Macs, geben Sie ⌘F9 ein. Es sollte kein Fehler vorliegen.

  • Die verbleibende Code-Änderung verfolgt den Status der Benutzer (sind sie angemeldet oder nicht angemeldet?) und löst den SignIn / SignUp Benutzer der Benutzeroberfläche aus, wenn er auf ein Schloss-Symbol klickt.

    a. Hinzufügen von signIn- und signOut-Methoden
    Fügen Sie an beliebiger Stelle in der Backend-Klasse die folgenden vier Methoden hinzu:
    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()) }
        )
    }

    Fügen Sie dann die erforderlichen Import-Anweisungen für jede fehlende Klassendefinition hinzu (Alt + Enter bei roten Wörtern). Wenn Sie die Wahl zwischen mehreren Klassen haben, wählen Sie unbedingt diejenige aus dem Amplify-Paket aus, wie auf dem Screenshot unten gezeigt.

    Beachten Sie, dass wir das Flag UserData.isSignedIn von diesen Methoden nicht aktualisieren, dies geschieht im nächsten Abschnitt.

    b. Hinzufügen eines Authentifizierungs-Hub-Listeners

    Um die Änderungen des Authentifizierungsstatus zu verfolgen, fügen wir Code hinzu, um die von Amplify gesendeten Authentifizierungsereignisse zu abonnieren. Wir initialisieren den Hub in der Methode Backend.initialize().

    Wenn ein Authentifizierungsereignis empfangen wird, rufen wir die Methode updateUserData() auf. Diese Methode hält das UserData-Objekt synchron. Die Eigenschaft UserData.isSignedIn ist eine LiveData<Boolean>, d.h. Beobachter, die diese Eigenschaft abonniert haben, werden benachrichtigt, wenn sich der Wert ändert. Wir verwenden diesen Mechanismus, um die Benutzeroberfläche automatisch zu aktualisieren. Mehr über LiveData erfahren Sie in der Android-Doku.

    Wir fügen auch Code hinzu, um den vorherigen Authentifizierungsstatus beim Start der Anwendung zu überprüfen. Wenn die Anwendung startet, prüft sie, ob bereits eine Cognito-Sitzung existiert und aktualisiert die UserData entsprechend.

    Fügen Sie in Backend.initialize() den folgenden Code nach dem try / catch-Block und vor der return-Anweisung ein.

    // 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()) }
    )

    Um zu überprüfen, ob alles wie erwartet funktioniert, erstellen Sie das Projekt. Klicken Sie auf das Menü Build und wählen Sie Projekt machen oder, auf Macs, geben Sie ⌘F9 ein. Es sollte kein Fehler vorliegen.

    c. Aktualisieren Sie den Code der Benutzeroberfläche

    Die letzte Änderung im Code bezieht sich auf die Benutzeroberfläche, wir fügen einen FloatingActionButton zur Hauptaktivität hinzu.

    Öffnen Sie unter res/layout die Datei activity_main.xml und ersetzen Sie den vorhandenen FloatingActionButton durch diesen:

    <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"
        />

    Fügen Sie ein Schloss-Symbol unter res/drawable hinzu. Klicken Sie mit der rechten Maustaste auf zeichenbar, wählen Sie Neu, dann Vektor-Asset. Wählen Sie das Schlosssymbol aus dem Clipart und geben Sie ic_baseline_lock (ohne den _24) als Namen ein und wählen Sie das geschlossene Schlosssymbol aus der Clip-Art. Klicken Sie auf Weiter und Beenden.

    Wiederholen Sie dasselbe mit dem Symbol für das offene Schloss.

    Danach sollten Sie die folgenden Dateien in Ihrem Drawable-Verzeichnis haben:

    Verknüpfen Sie nun die neu erstellte Schaltfläche im Code. Öffnen Sie unter java/com.example.androidgettingstarted/ die Datei MainActivity.kt und fügen Sie den folgenden Code hinzu.

    // 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)
            }
        }
    }

    Fügen Sie, immer noch in MainActivity, den folgenden Code am Ende der Methode onCreate() hinzu:

    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)
        }
    })

    Der obige Code registriert einen Beobachter auf dem Wert Userdata.isSignedIn. Die Schließung wird aufgerufen, wenn sich der isSignedIn-Wert ändert. Im Moment ändern wir nur das Schloss-Symbol: offen, wenn der Benutzer authentifiziert ist, und geschlossen, wenn der Benutzer keine Sitzung hat.

    Um zu überprüfen, ob alles wie erwartet funktioniert, erstellen Sie das Projekt. Klicken Sie auf das Menü Build und wählen Sie Projekt machen oder, auf Macs, geben Sie ⌘F9 ein. Es sollte kein Fehler vorliegen.

    d. AndroidManifest.xml und MainActivity aktualisieren

    Schließlich müssen wir sicherstellen, dass unsere Anwendung am Ende der Web-Authentifizierungssequenz, die von der von Cognito gehosteten Benutzeroberfläche bereitgestellt wird, gestartet wird. Wir fügen in der Manifestdatei eine neue Aktivität hinzu. Die Aktivität wird aufgerufen, wenn das eingeführte URI-Schema empfangen wird.

    Öffnen Sie in Android Studio unter "Manifeste" die Datei AndroidManifest.xml und fügen Sie die unten stehende Aktivität innerhalb des Anwendungselements hinzu.

        <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>
    

    Öffnen Sie unter java/com.example.androidgettingstarted/ die Datei MainActivity.kt und fügen Sie den folgenden Code an beliebiger Stelle in der Klasse hinzu.

    // 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)
    }

    Öffnen Sie unter java/com.example.androidgettingstarted/ die Datei Backend.kt und fügen Sie den folgenden Code an einer beliebigen Stelle in der Klasse ein.

    // 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. Erstellen und testen

    Um zu überprüfen, ob alles wie erwartet funktioniert, bauen und betreiben Sie das Projekt. Klicken Sie auf das Symbol Ausführen ▶️ in der Symbolleiste oder geben Sie ^ R ein. Es sollte kein Fehler vorliegen. Die App wird gestartet, und unten rechts auf dem Bildschirm befindet sich eine schwebende Schaltfläche mit geschlossenem Schloss.

    Hier ist der vollständige Anmeldungsablauf:

Fazit

Mit nur wenigen Zeilen Code haben Sie jetzt die Benutzerauthentifizierung in Ihre Anwendung integriert! Im nächsten Modul werden wir eine API zu Ihrer Anwendung hinzufügen.

War das Modul hilfreich?

GraphQL-API und -Datenbank hinzufügen