Zanim użytkownicy będą mogli uwierzytelniać się za pomocą kluczy dostępu, Twoja aplikacja musi najpierw zarejestrować lub utworzyć klucz dostępu dla ich konta.
Aby utworzyć klucz dostępu, pobierz z serwera aplikacji szczegóły wymagane do utworzenia klucza dostępu, a następnie wywołaj interfejs Credential Manager API, który zwraca parę kluczy publiczny-prywatny. Zwrócony klucz prywatny jest przechowywany u dostawcy danych logowania, np. w Menedżerze haseł Google, jako klucz dostępu. Klucz publiczny jest przechowywany na serwerze aplikacji.
Wymagania wstępne
Upewnij się, że masz skonfigurowane Digital Asset Links i kierujesz aplikację na urządzenia z Androidem 9 (API na poziomie 28) lub nowszym.
Omówienie
Ten przewodnik skupia się na zmianach, które należy wprowadzić w aplikacji klienta podmiotu ufającego, aby utworzyć klucz dostępu. Zawiera też krótkie omówienie implementacji serwera aplikacji podmiotu ufającego. Więcej informacji o integracji po stronie serwera znajdziesz w artykule Rejestracja klucza dostępu po stronie serwera.
- Dodaj zależności do aplikacji: dodaj wymagane biblioteki Menedżera danych logowania.
- Utwórz instancję Credential Manager: utwórz instancję Credential Manager.
- Pobierz z serwera aplikacji opcje tworzenia danych logowania: z serwera aplikacji wyślij do aplikacji klienta szczegóły wymagane do utworzenia klucza dostępu, takie jak informacje o aplikacji i użytkowniku, a także
challengei inne pola. - Poproś o klucz dostępu: w aplikacji użyj szczegółów otrzymanych z serwera aplikacji, aby utworzyć obiekt
GetPublicKeyCredentialOption, a następnie użyj tego obiektu do wywołania metodycredentialManager.getCredential()w celu utworzenia klucza dostępu. - Obsługa odpowiedzi na utworzenie klucza dostępu: gdy otrzymasz dane logowania w aplikacji klienckiej, musisz zakodować i zserializować klucz publiczny, a następnie wysłać go na serwer aplikacji. Musisz też obsłużyć wszystkie wyjątki, które mogą wystąpić w przypadku tworzenia klucza dostępu.
- Zweryfikuj i zapisz klucz publiczny na serwerze: wykonaj czynności po stronie serwera, aby zweryfikować pochodzenie danych logowania, a następnie zapisz klucz publiczny.
- Powiadom użytkownika: powiadom użytkownika o utworzeniu klucza dostępu.
1. Dodawanie zależności do aplikacji
Dodaj te zależności do pliku build.gradle modułu aplikacji:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.6.0-beta03") implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta03") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.6.0-beta03" implementation "androidx.credentials:credentials-play-services-auth:1.6.0-beta03" }
2. Utwórz instancję Menedżera danych logowania
Użyj aplikacji lub kontekstu aktywności, aby utworzyć obiekt CredentialManager.
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
3. Uzyskiwanie opcji tworzenia danych logowania z serwera aplikacji
Gdy użytkownik kliknie przycisk „Utwórz klucz dostępu” lub gdy nowy użytkownik zarejestruje się, wyślij z aplikacji do serwera aplikacji żądanie uzyskania informacji potrzebnych do rozpoczęcia procesu rejestracji klucza dostępu.
Użyj na serwerze aplikacji biblioteki zgodnej z FIDO, aby wysłać do aplikacji klienckiej informacje wymagane do utworzenia klucza dostępu, takie jak informacje o użytkowniku, aplikacji i dodatkowe właściwości konfiguracji. Więcej informacji znajdziesz w artykule Rejestracja klucza dostępu po stronie serwera.
W aplikacji klienckiej zdekoduj opcje tworzenia klucza publicznego wysłane przez serwer aplikacji. Zazwyczaj są one przedstawiane w formacie JSON. Więcej informacji o tym, jak dekodowanie jest przeprowadzane w przypadku klientów internetowych, znajdziesz w artykule Kodowanie i dekodowanie. W przypadku aplikacji klienckich na Androida dekodowanie musisz obsługiwać osobno.
Poniższy fragment kodu pokazuje strukturę opcji tworzenia klucza publicznego wysyłanych przez serwer aplikacji:
{
"challenge": "<base64url-encoded challenge>",
"rp": {
"name": "<relying party name>",
"id": "<relying party host name>"
},
"user": {
"id": "<base64url-encoded user ID>",
"name": "<user name>",
"displayName": "<user display name>"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
}
],
"attestation": "none",
"excludeCredentials": [
{
"id": "<base64url-encoded credential ID to exclude>",
"type": "public-key"
}
],
"authenticatorSelection": {
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
Kluczowe pola w opcjach tworzenia klucza publicznego to:
challenge: losowy ciąg znaków generowany przez serwer, który służy do zapobiegania atakom typu replay.rp: szczegóły aplikacji.rp.name: nazwa aplikacji.rp.id: domena lub subdomena aplikacji.
user: szczegóły dotyczące użytkownika.id: unikalny identyfikator użytkownika. Ta wartość nie może zawierać informacji umożliwiających identyfikację, np. adresów e-mail ani nazw użytkowników. Możesz użyć losowej 16-bajtowej wartości.name: Unikalny identyfikator konta, który użytkownik rozpozna, np. adres e-mail lub nazwa użytkownika. Będzie on widoczny w selektorze kont. Jeśli używasz nazwy użytkownika, użyj tej samej wartości co w przypadku uwierzytelniania za pomocą hasła.displayName: Opcjonalna, przyjazna dla użytkownika nazwa konta, która ma być wyświetlana w selektorze kont.
authenticatorSelection: szczegóły urządzenia, które będzie używane do uwierzytelniania.authenticatorAttachment: wskazuje preferowany uwierzytelniacz. Dostępne są te wartości: –platform: ta wartość jest używana w przypadku uwierzytelniania wbudowanego w urządzenie użytkownika, np. czytnika linii papilarnych. -cross-platform: ta wartość jest używana w przypadku urządzeń mobilnych, takich jak klucze bezpieczeństwa. Nie jest on zwykle używany w kontekście kluczy dostępu. – Nieokreślone (zalecane): pozostawienie tej wartości nieokreślonej zapewnia użytkownikom elastyczność w zakresie tworzenia kluczy dostępu na preferowanych urządzeniach. W większości przypadków najlepszym rozwiązaniem jest pozostawienie tego parametru bez podanej wartości.requireResidentKey: aby utworzyć klucz dostępu, ustaw wartość tego polaBooleannatrue.residentKey: aby utworzyć klucz dostępu, ustaw wartość narequired.userVerification: służy do określania wymagań dotyczących weryfikacji użytkownika podczas rejestracji klucza dostępu. Możliwe wartości są następujące: –preferred: użyj tej wartości, jeśli priorytetem jest wygoda użytkownika, a nie ochrona, np. w środowiskach, w których weryfikacja użytkownika powoduje więcej problemów niż ochrona. -required: użyj tej wartości, jeśli wymagane jest wywołanie metody weryfikacji użytkownika dostępnej na urządzeniu. -discouraged: użyj tej wartości, jeśli korzystanie z metody weryfikacji użytkownika jest odradzane.
Więcej informacji znajdziesz wuserVerificationszczegółowym omówieniu weryfikacji użytkownika.
excludeCredentials: Wymień identyfikatory danych logowania w tablicy, aby zapobiec utworzeniu zduplikowanego klucza dostępu, jeśli istnieje już klucz dostępu u tego samego dostawcy danych logowania.
4. Poproś o klucz dostępu
Po przeanalizowaniu opcji tworzenia klucza publicznego po stronie serwera utwórz klucz dostępu, umieszczając te opcje w obiekcie CreatePublicKeyCredentialRequest i wywołując createCredential().
createPublicKeyCredentialRequest obejmuje:
requestJson: opcje tworzenia danych logowania wysłane przez serwer aplikacji.preferImmediatelyAvailableCredentials: to opcjonalne pole logiczne, które określa, czy do realizacji żądania należy używać tylko dostępnych lokalnie lub zsynchronizowanych z dostawcą danych logowania danych logowania, zamiast danych logowania z kluczy bezpieczeństwa lub hybrydowych kluczy. Możliwe zastosowania są następujące:false(domyślna): użyj tej wartości, jeśli wywołanie Menedżera danych logowania zostało wywołane przez wyraźne działanie użytkownika.true: użyj tej wartości, jeśli Menedżer danych logowania jest wywoływany w sposób oportunistyczny, np. przy pierwszym otwarciu aplikacji.
Jeśli ustawisz wartość natruei nie ma od razu dostępnych danych logowania, Menedżer danych logowania nie wyświetli żadnego interfejsu, a żądanie natychmiast się nie powiedzie, zwracając NoCredentialException w przypadku żądań pobierania iCreateCredentialNoCreateOptionExceptionw przypadku żądań tworzenia.
origin: to pole jest ustawiane automatycznie w przypadku aplikacji na Androida. W przypadku przeglądarek i podobnych aplikacji z uprawnieniami, które muszą ustawićorigin, zobacz Wykonywanie wywołań Credential Manager w imieniu innych podmiotów w przypadku aplikacji z uprawnieniami.isConditional: to pole opcjonalne, którego wartość domyślna tofalse. Jeśli ustawisz tę opcję natrue, a użytkownik nie będzie mieć klucza dostępu, automatycznie utworzysz go w jego imieniu przy następnym logowaniu się za pomocą zapisanego hasła. Klucz dostępu jest przechowywany u dostawcy danych logowania użytkownika. Funkcja warunkowego tworzenia wymaga najnowszej wersjiandroidx.credentials.
Wywołanie funkcji createCredential() powoduje uruchomienie wbudowanego interfejsu Credential Managera w postaci arkusza u dołu ekranu, który wyświetla użytkownikowi prośbę o użycie klucza dostępu i wybranie dostawcy danych logowania oraz konta do przechowywania. Jeśli jednak wartość isConditional jest ustawiona na true, interfejs arkusza u dołu nie jest wyświetlany, a klucz dostępu jest tworzony automatycznie.
5. Obsługa odpowiedzi
Po zweryfikowaniu użytkownika za pomocą blokady ekranu urządzenia tworzony jest klucz dostępu, który jest przechowywany u wybranego dostawcy danych logowania.
Odpowiedź po pomyślnym wywołaniu funkcji createCredential() to obiekt PublicKeyCredential.
PublicKeyCredential wygląda tak:
{
"id": "<identifier>",
"type": "public-key",
"rawId": "<identifier>",
"response": {
"clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
"attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
},
"authenticatorAttachment": "platform"
}
W aplikacji klienckiej serializuj obiekt i wyślij go na serwer aplikacji.
Dodaj kod obsługujący błędy, jak pokazano w tym fragmencie:
fun handleFailure(e: CreateCredentialException) {
when (e) {
is CreatePublicKeyCredentialDomException -> {
// Handle the passkey DOM errors thrown according to the
// WebAuthn spec.
}
is CreateCredentialCancellationException -> {
// The user intentionally canceled the operation and chose not
// to register the credential.
}
is CreateCredentialInterruptedException -> {
// Retry-able error. Consider retrying the call.
}
is CreateCredentialProviderConfigurationException -> {
// Your app is missing the provider configuration dependency.
// Most likely, you're missing the
// "credentials-play-services-auth" module.
}
is CreateCredentialCustomException -> {
// You have encountered an error from a 3rd-party SDK. If you
// make the API call with a request object that's a subclass of
// CreateCustomCredentialRequest using a 3rd-party SDK, then you
// should check for any custom exception type constants within
// that SDK to match with e.type. Otherwise, drop or log the
// exception.
}
else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}")
}
}
6. Weryfikowanie i zapisywanie klucza publicznego na serwerze aplikacji
Na serwerze aplikacji musisz zweryfikować dane logowania klucza publicznego, a następnie zapisać klucz publiczny.
Aby zweryfikować pochodzenie danych logowania za pomocą klucza publicznego, porównaj je z listą dozwolonych aplikacji. Jeśli klucz ma nierozpoznane pochodzenie, odrzuć go.
Aby uzyskać odcisk cyfrowy SHA-256 aplikacji:
Wydrukuj certyfikat podpisywania aplikacji w wersji produkcyjnej, uruchamiając w terminalu to polecenie:
keytool -list -keystore <path-to-apk-signing-keystore>W odpowiedzi podaj odcisk cyfrowy SHA-256 certyfikatu podpisywania, oznaczony jako
Certificate fingerprints block:SHA256.Zakoduj odcisk cyfrowy SHA256 za pomocą kodowania base64url. Ten przykład w Pythonie pokazuje, jak prawidłowo zakodować odcisk palca:
import binascii import base64 fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))Dodaj
android:apk-key-hash: na początku danych wyjściowych z poprzedniego kroku, aby uzyskać wynik podobny do tego:android:apk-key-hash:<encoded SHA 256 fingerprint>Wynik powinien być zgodny z dozwolonym źródłem na serwerze aplikacji. Jeśli masz kilka certyfikatów podpisywania, np. certyfikaty do debugowania i wersji, lub kilka aplikacji, powtórz ten proces i zaakceptuj wszystkie pochodzenia jako prawidłowe na serwerze aplikacji.
7. Powiadomienie użytkownika
Po utworzeniu klucza dostępu powiadom użytkowników o tym, że mogą zarządzać kluczami dostępu w aplikacji dostawcy danych logowania lub w ustawieniach aplikacji. Powiadamiaj użytkowników za pomocą niestandardowego okna, powiadomienia lub paska powiadomień. Nieoczekiwane utworzenie klucza dostępu przez złośliwy podmiot wymaga natychmiastowego alertu bezpieczeństwa, dlatego warto uzupełnić te metody w aplikacji o komunikację zewnętrzną, np. e-mail.
Ulepszanie wrażeń użytkowników
Aby zwiększyć wygodę użytkowników podczas wdrażania rejestracji za pomocą Credential Manager, rozważ dodanie funkcji przywracania danych logowania i ukrywania okien autouzupełniania.
Dodanie funkcji przywracania danych logowania na nowym urządzeniu
Aby umożliwić użytkownikom bezproblemowe logowanie się na konta na nowych urządzeniach, wdróż funkcję Przywróć dane logowania. Dodanie danych logowania do przywracania
BackupAgent umożliwia użytkownikom zalogowanie się po otwarciu przywróconej aplikacji na nowym urządzeniu
i natychmiastowe korzystanie z niej.
Pomijanie autouzupełniania w polach danych logowania (opcjonalnie)
W przypadku ekranów aplikacji, na których użytkownicy mają używać interfejsu arkusza dolnego Menedżera danych logowania do uwierzytelniania, dodaj atrybut isCredential do pól nazwy użytkownika i hasła. Zapobiega to nakładaniu się okien autouzupełniania (FillDialog i SaveDialog) na interfejs planszy dolnej Credential Manager.
Atrybut isCredential jest obsługiwany na urządzeniach z Androidem 14 lub nowszym.
W przykładzie poniżej pokazujemy, jak dodać atrybut isCredential do odpowiednich pól nazwy użytkownika i hasła w odpowiednich widokach aplikacji:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true" />
Dalsze kroki
- Logowanie się za pomocą kluczy dostępu
- Zarządzanie kluczami dostępu
- Poznawanie ścieżek użytkowników kluczy dostępu