![Diagramm der Authentifizierungstoken-Logik](https://developer.android.com/static/images/training/oauth_dance.png?authuser=8&hl=de)
Für den sicheren Zugriff auf einen Onlinedienst müssen sich Nutzer beim Dienst authentifizieren und einen Identitätsnachweis vorlegen. Bei Anwendungen, die auf Drittanbieterdienste zugreifen, ist das Sicherheitsproblem noch komplizierter. Der Nutzer muss nicht nur authentifiziert sein, um auf den Dienst zugreifen zu können. Die Anwendung muss auch autorisiert sein, im Namen des Nutzers zu handeln.
Das Branchenstandard für die Authentifizierung bei Drittanbieterdiensten ist das OAuth2-Protokoll. OAuth2 stellt einen einzelnen Wert bereit, der als Authentifizierungstoken bezeichnet wird und sowohl die Identität des Nutzers als auch die Autorisierung der Anwendung angibt, im Namen des Nutzers zu handeln. In dieser Lektion wird die Verbindung zu einem Google-Server hergestellt, der OAuth2 unterstützt. Obwohl Google-Dienste als Beispiel verwendet werden, funktionieren die gezeigten Techniken auch bei allen Diensten, die das OAuth2-Protokoll korrekt unterstützen.
Die Verwendung von OAuth2 eignet sich für Folgendes:
- Berechtigung vom Nutzer einholen, um mit seinem Konto auf einen Onlinedienst zuzugreifen
- Authentifizierung bei einem Online-Dienst im Namen des Nutzers.
- Authentifizierungsfehler verarbeiten
Informationen sammeln
Um mit der Verwendung von OAuth2 beginnen zu können, müssen Sie einige API-spezifische Informationen zu dem Dienst wissen, auf den Sie zugreifen möchten:
- Die URL des Dienstes, auf den Sie zugreifen möchten.
- Der Authentifizierungsbereich. Dabei handelt es sich um einen String, der den spezifischen Zugriffstyp definiert, den Ihre Anwendung anfordert. Beispielsweise ist der Authentifizierungsbereich für den Lesezugriff auf Google Tasks
View your tasks
und der Authentifizierungsbereich für den Lese-/Schreibzugriff auf Google TasksManage your tasks
. - Eine Client-ID und ein Clientschlüssel. Dabei handelt es sich um Strings, die Ihre Anwendung gegenüber dem Dienst identifizieren. Sie erhalten diese Strings direkt vom Dienstinhaber. Google hat ein Self-Service-System zum Abrufen von Client-IDs und -Secrets.
Internetberechtigung anfordern
Für Apps, die auf Android 6.0 (API-Level 23) und höher ausgerichtet sind, sind für die Methode getAuthToken()
selbst keine Berechtigungen erforderlich. Um Vorgänge mit dem Token ausführen zu können, müssen Sie Ihrer Manifestdatei jedoch die Berechtigung INTERNET
hinzufügen, wie im folgenden Code-Snippet gezeigt:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Authentifizierungstoken anfordern
Rufen Sie AccountManager.getAuthToken()
auf, um das Token abzurufen.
Achtung : Da einige Kontovorgänge unter Umständen Netzwerkkommunikation umfassen, sind die meisten AccountManager
-Methoden asynchron. Das bedeutet, dass Sie nicht die gesamte Authentifizierungsarbeit in einer Funktion ausführen müssen, sondern sie als eine Reihe von Callbacks implementieren müssen.
Das folgende Snippet zeigt, wie Sie mit einer Reihe von Callbacks arbeiten, um das Token abzurufen:
Kotlin
val am: AccountManager = AccountManager.get(this) val options = Bundle() am.getAuthToken( myAccount_, // Account retrieved using getAccountsByType() "Manage your tasks", // Auth scope options, // Authenticator-specific options this, // Your activity OnTokenAcquired(), // Callback called when a token is successfully acquired Handler(OnError()) // Callback called if an error occurs )
Java
AccountManager am = AccountManager.get(this); Bundle options = new Bundle(); am.getAuthToken( myAccount_, // Account retrieved using getAccountsByType() "Manage your tasks", // Auth scope options, // Authenticator-specific options this, // Your activity new OnTokenAcquired(), // Callback called when a token is successfully acquired new Handler(new OnError())); // Callback called if an error occurs
In diesem Beispiel ist OnTokenAcquired
eine Klasse, die AccountManagerCallback
implementiert. AccountManager
ruft run()
für OnTokenAcquired
mit einer AccountManagerFuture
auf, die ein Bundle
enthält. Wenn der Aufruf erfolgreich war, befindet sich das Token im Bundle
.
So rufen Sie das Token aus dem Bundle
ab:
Kotlin
private class OnTokenAcquired : AccountManagerCallback<Bundle> { override fun run(result: AccountManagerFuture<Bundle>) { // Get the result of the operation from the AccountManagerFuture. val bundle: Bundle = result.getResult() // The token is a named value in the bundle. The name of the value // is stored in the constant AccountManager.KEY_AUTHTOKEN. val token: String = bundle.getString(AccountManager.KEY_AUTHTOKEN) } }
Java
private class OnTokenAcquired implements AccountManagerCallback<Bundle> { @Override public void run(AccountManagerFuture<Bundle> result) { // Get the result of the operation from the AccountManagerFuture. Bundle bundle = result.getResult(); // The token is a named value in the bundle. The name of the value // is stored in the constant AccountManager.KEY_AUTHTOKEN. String token = bundle.getString(AccountManager.KEY_AUTHTOKEN); ... } }
Wenn alles gut läuft, enthält Bundle
ein gültiges Token im Schlüssel KEY_AUTHTOKEN
und Sie sind startklar.
Ihre erste Anforderung eines Authentifizierungstokens kann aus mehreren Gründen fehlschlagen:
- Ein Fehler im Gerät oder Netzwerk hat dazu geführt, dass
AccountManager
fehlgeschlagen ist. - Der Nutzer hat Ihrer App keinen Zugriff auf das Konto gewährt.
- Die gespeicherten Anmeldedaten reichen für den Zugriff auf das Konto nicht aus.
- Das im Cache gespeicherte Authentifizierungstoken ist abgelaufen.
Die ersten beiden Fälle können in der Regel ganz einfach verarbeitet werden, indem dem Nutzer einfach eine Fehlermeldung angezeigt wird. Wenn das Netzwerk ausgefallen ist oder der Nutzer keinen Zugriff gewährt, kann Ihre Anwendung nicht viel dagegen tun. Die letzten beiden Fälle sind etwas komplizierter, da von gut funktionierenden Anwendungen erwartet wird, dass sie diese Fehler automatisch verarbeiten.
Der dritte Fehlerfall, also unzureichende Anmeldedaten, wird über den Bundle
kommuniziert, den Sie in Ihrem AccountManagerCallback
erhalten (OnTokenAcquired
im vorherigen Beispiel). Wenn der Bundle
ein Intent
im Schlüssel KEY_INTENT
enthält, teilt Ihnen der Authenticator mit, dass er direkt mit dem Nutzer interagieren muss, bevor er Ihnen ein gültiges Token liefern kann.
Es kann viele Gründe dafür geben, dass der Authenticator ein Intent
zurückgibt. Möglicherweise hat sich der Nutzer zum ersten Mal in diesem Konto angemeldet. Möglicherweise ist das Konto des Nutzers abgelaufen und er muss sich noch einmal anmelden oder seine gespeicherten Anmeldedaten sind falsch. Vielleicht erfordert das Konto eine 2-Faktor-Authentifizierung oder die Kamera muss für einen Netzhautscan aktiviert werden. Es spielt keine Rolle, was der Grund ist. Wenn Sie ein gültiges Token benötigen, müssen Sie das Intent
auslösen, um es abzurufen.
Kotlin
private inner class OnTokenAcquired : AccountManagerCallback<Bundle> { override fun run(result: AccountManagerFuture<Bundle>) { val launch: Intent? = result.getResult().get(AccountManager.KEY_INTENT) as? Intent if (launch != null) { startActivityForResult(launch, 0) } } }
Java
private class OnTokenAcquired implements AccountManagerCallback<Bundle> { @Override public void run(AccountManagerFuture<Bundle> result) { ... Intent launch = (Intent) result.getResult().get(AccountManager.KEY_INTENT); if (launch != null) { startActivityForResult(launch, 0); return; } } }
Im Beispiel wird startActivityForResult()
verwendet. Sie können also das Ergebnis von Intent
erfassen, indem Sie onActivityResult()
in Ihrer eigenen Aktivität implementieren. Wichtig: Wenn Sie das Ergebnis nicht aus der Antwort Intent
des Authenticators erfassen, lässt sich nicht feststellen, ob der Nutzer erfolgreich authentifiziert wurde.
Wenn das Ergebnis RESULT_OK
ist, hat die Authentifizierungs-App die gespeicherten Anmeldedaten aktualisiert, sodass sie für die angeforderte Zugriffsebene ausreichend sind. Sie sollten AccountManager.getAuthToken()
noch einmal aufrufen, um das neue Authentifizierungstoken anzufordern.
Der letzte Fall, bei dem das Token abgelaufen ist, ist tatsächlich kein AccountManager
-Fehler. Die einzige Möglichkeit herauszufinden, ob ein Token abgelaufen ist, besteht darin, den Server zu kontaktieren. Es wäre verschwenderisch und teuer, wenn AccountManager
ständig online geht, um den Status aller seiner Tokens zu prüfen. Dieser Fehler kann also nur erkannt werden, wenn eine Anwendung wie Ihre versucht, das Authentifizierungstoken für den Zugriff auf einen Onlinedienst zu verwenden.
Verbindung zum Onlinedienst herstellen
Das folgende Beispiel zeigt, wie Sie eine Verbindung zu einem Google-Server herstellen. Da Google das branchenübliche OAuth2-Protokoll zur Authentifizierung von Anfragen verwendet, sind die hier beschriebenen Techniken allgemein anwendbar. Denken Sie jedoch daran, dass jeder Server anders ist. Möglicherweise müssen Sie kleinere Anpassungen an dieser Anleitung vornehmen, um Ihrer spezifischen Situation gerecht zu werden.
Bei den Google APIs müssen Sie für jede Anfrage vier Werte angeben: den API-Schlüssel, die Client-ID, den Clientschlüssel und den Authentifizierungsschlüssel. Die ersten drei stammen von der Website der Google API Console. Der letzte ist der Stringwert, den Sie durch Aufrufen von AccountManager.getAuthToken()
erhalten haben. Diese werden als Teil einer HTTP-Anfrage an den Google-Server übergeben.
Kotlin
val url = URL("https://www.googleapis.com/tasks/v1/users/@me/lists?key=$your_api_key") val conn = url.openConnection() as HttpURLConnection conn.apply { addRequestProperty("client_id", your client id) addRequestProperty("client_secret", your client secret) setRequestProperty("Authorization", "OAuth $token") }
Java
URL url = new URL("https://www.googleapis.com/tasks/v1/users/@me/lists?key=" + your_api_key); URLConnection conn = (HttpURLConnection) url.openConnection(); conn.addRequestProperty("client_id", your client id); conn.addRequestProperty("client_secret", your client secret); conn.setRequestProperty("Authorization", "OAuth " + token);
Wenn die Anfrage den HTTP-Fehlercode 401 zurückgibt, wurde Ihr Token abgelehnt. Wie im letzten Abschnitt erwähnt, ist der häufigste Grund dafür, dass das Token abgelaufen ist. Die Lösung ist einfach: Rufen Sie AccountManager.invalidateAuthToken()
auf und wiederholen Sie den Vorgang zum Abrufen des Tokens noch einmal.
Da abgelaufene Tokens so häufig vorkommen und deren Behebung so einfach ist, gehen viele Anwendungen einfach davon aus, dass das Token abgelaufen ist, bevor sie danach fragen. Wenn das Erneuern eines Tokens für Ihren Server ein kostengünstiger Vorgang ist, sollten Sie AccountManager.invalidateAuthToken()
vor dem ersten Aufruf von AccountManager.getAuthToken()
aufrufen und es nicht notwendig machen, zweimal ein Authentifizierungstoken anzufordern.