Dowiedz się, jak uprościć ścieżki uwierzytelniania za pomocą interfejsu Credential Manager API w swojej aplikacji na Androida

1. Zanim zaczniesz

Tradycyjne rozwiązania do uwierzytelniania wiążą się z wieloma wyzwaniami w zakresie bezpieczeństwa i łatwości obsługi.

Hasła są powszechnie używane, ale...

  • Łatwo zapomnieć
  • Użytkownicy potrzebują wiedzy do tworzenia silnych haseł.
  • Łatwość ataku, zbierania i ponownego wykorzystania przez hakerów.

Android pracował nad utworzeniem interfejsu Credential Manager API, aby uprościć logowanie i eliminować zagrożenia dzięki obsłudze kluczy dostępu – nowej generacji standardu branżowego uwierzytelniania bez hasła.

Menedżer danych logowania łączy obsługę kluczy dostępu z tradycyjnymi metodami uwierzytelniania, takimi jak hasła czy funkcja Zaloguj się przez Google.

Użytkownicy będą mogli tworzyć klucze dostępu i przechowywać je w Menedżerze haseł Google, który synchronizuje te klucze dostępu na urządzeniach z Androidem, na których jest zalogowany użytkownik. Aby użytkownik mógł się zalogować, klucz publiczny musi zostać utworzony i powiązany z kontem użytkownika oraz zapisany na serwerze jego klucz publiczny.

Z tego ćwiczenia w Codelabs dowiesz się, jak rejestrować się przy użyciu kluczy dostępu i hasła za pomocą interfejsu Credential Manager API oraz jak używać ich do uwierzytelniania w przyszłości. Wyróżniamy 2 procesy, w tym:

  • Zarejestruj się : za pomocą kluczy dostępu i hasła.
  • Logowanie się : za pomocą kluczy dostępu i zapisane hasło.

Wymagania wstępne

  • Podstawowa znajomość sposobu uruchamiania aplikacji w Android Studio.
  • Podstawowa znajomość procesu uwierzytelniania w aplikacjach na Androida.
  • Podstawowa znajomość kluczy dostępu.

Czego się nauczysz

  • Jak utworzyć klucz dostępu.
  • Jak zapisać hasło w menedżerze haseł.
  • Jak uwierzytelniać użytkowników za pomocą klucza dostępu lub zapisanego hasła.

Czego potrzebujesz

Jedna z tych kombinacji urządzeń:

  • Urządzenie z Androidem z Androidem 9 lub nowszym (w przypadku kluczy dostępu) i Androidem 4.4 lub nowszym(do uwierzytelniania za pomocą hasła przez interfejs Credential Manager API).
  • Najlepiej z czujnikiem biometrycznym.
  • Pamiętaj, aby zarejestrować urządzenie biometryczne (lub blokadę ekranu).
  • Wersja wtyczki Kotlin : 1.8.10

2. Konfiguracja

  1. Skopiuj na laptopie to repozytorium z gałęzi credman_codelab : https://github.com/android/identity-samples/tree/credman_codelab
  2. Przejdź do modułu CredentialManager i otwórz projekt w Android Studio.

Sprawdzanie początkowego stanu aplikacji

Aby sprawdzić, jak działa początkowy stan aplikacji, wykonaj te czynności:

  1. Uruchom aplikację.
  2. Zobaczysz ekran główny z przyciskiem „Zarejestruj się i zaloguj”.
  3. Możesz kliknąć Zarejestruj się, aby się zarejestrować za pomocą klucza dostępu lub hasła.
  4. Możesz kliknąć Zaloguj się, aby się zalogować, używając klucza dostępu i zapisane hasło.

8c0019ff9011950a.jpeg

Aby dowiedzieć się, czym są klucze dostępu i jak działają, przeczytaj artykuł Jak działają klucze dostępu? .

3. Dodaj możliwość rejestracji za pomocą kluczy dostępu

Podczas rejestrowania nowego konta w aplikacji na Androida, która używa interfejsu Credential Manager API, użytkownicy mogą utworzyć klucz dostępu do swojego konta. Ten klucz dostępu będzie bezpiecznie przechowywany u dostawcy danych uwierzytelniających wybranego użytkownika i używany przy kolejnych logowaniach bez konieczności każdorazowego wprowadzania hasła.

Teraz utworzysz klucz dostępu i zarejestrujesz dane logowania użytkownika za pomocą biometrii lub blokady ekranu.

Zarejestruj się za pomocą klucza dostępu

Inside Credential Manager -> aplikacja -> główny -> java -> SignUpFragment.kt, zobaczysz pole tekstowe „username” i przycisk rejestracji za pomocą klucza dostępu.

dcc5c529b310f2fb.jpeg

Przekaż test zabezpieczający i inną odpowiedź JSON do wywołania createPasskey()

Przed utworzeniem klucza dostępu musisz zażądać od serwera uzyskania niezbędnych informacji, które należy przekazać do interfejsu Credential Manager API podczas wywoływania funkcji createCredential().

Na szczęście masz już w swoich zasobach przykładową odpowiedź(RegFromServer.txt), która zwraca takie parametry w tym ćwiczeniu w Codelabs.

  • W aplikacji przejdź do metody SignUpFragment.kt, Find, signUpWithPasskeys, aby zapisać logikę tworzenia klucza dostępu i zezwalania użytkownikowi na dostęp. Tę metodę znajdziesz w tej samej klasie.
  • Zaznacz blok Other z komentarzem, aby wywołać funkcję createPasskey() i zastąp ją następującym kodem :

SignUpFragment.kt

//TODO : Call createPasskey() to signup with passkey

val data = createPasskey()

Ta metoda zostanie wywołana po wpisaniu na ekranie prawidłowej nazwy użytkownika.

  • W metodzie createPasskey() musisz utworzyć funkcję CreatePublicKeyCredentialRequest() ze zwróconymi niezbędnymi parametrami.

SignUpFragment.kt

//TODO create a CreatePublicKeyCredentialRequest() with necessary registration json from server

val request = CreatePublicKeyCredentialRequest(fetchRegistrationJsonFromServer())

Jest to metoda, która odczytuje odpowiedź JSON rejestracji z zasobów i zwraca plik JSON rejestracji, który zostanie przekazany podczas tworzenia klucza dostępu.

  • Znajdź metodę downloadRegistrationJsonFromServer() i zastąp polecenie TODO poniższym kodem, aby zwrócić kod json, a także usunąć instrukcję zwracającą pusty ciąg znaków :

SignUpFragment.kt

//TODO fetch registration mock response

val response = requireContext().readFromAsset("RegFromServer")

//Update userId,challenge, name and Display name in the mock
return response.replace("<userId>", getEncodedUserId())
   .replace("<userName>", binding.username.text.toString())
   .replace("<userDisplayName>", binding.username.text.toString())
   .replace("<challenge>", getEncodedChallenge())
  • Znajdziesz tu informacje o rejestracji w pliku JSON z zasobami.
  • Ten plik JSON ma 4 pola do zastąpienia.
  • Identyfikator UserId musi być unikalny, aby użytkownik mógł utworzyć wiele kluczy dostępu (w razie potrzeby). Zastępujesz identyfikator użytkownika <userId> z wygenerowanym identyfikatorem użytkownika.
  • &lt;challenge&gt; musi być unikalny, więc zostanie wygenerowany losowe, unikalne wyzwanie. Metoda jest już w kodzie.

Ten fragment kodu zawiera przykładowe opcje otrzymane z serwera:

{
  "challenge": String,
  "rp": {
    "name": String,
    "id": String
  },
  "user": {
    "id": String,
    "name": String,
    "displayName": String
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

Poniższa tabela nie jest wyczerpująca, ale zawiera ważne parametry w słowniku PublicKeyCredentialCreationOptions:

Parametry

Teksty reklam

challenge

Wygenerowany przez serwer losowy ciąg o wystarczającej entropii, aby odgadnięcie go było niemożliwe. Powinien mieć co najmniej 16 bajtów. Jest to wymagane, ale nie jest używane podczas rejestracji, chyba że wykonujesz poświadczenie.

user.id

Unikalny identyfikator użytkownika. Ta wartość nie może zawierać informacji umożliwiających identyfikację, takich jak adresy e-mail czy nazwy użytkowników. Przyda się 16-bajtowa losowa wartość generowana dla każdego konta.

user.name

To pole powinno zawierać unikalny identyfikator konta rozpoznawany przez użytkownika, np. adres e-mail lub nazwę użytkownika. Będzie to widoczne w selektorze kont. Jeśli używasz nazwy użytkownika, użyj takiej samej wartości jak w przypadku uwierzytelnienia za pomocą hasła.

user.displayName

To pole jest opcjonalną, prostszą w użyciu nazwą konta. Jest to łatwa do odczytania przez człowieka nazwa konta użytkownika, przeznaczona tylko do wyświetlania.

rp.id

Podmiot uzależniający odpowiada szczegółowym informacjom zawartym w zgłoszeniu.Potrzebny jest :

  • nazwa (wymagana): nazwa aplikacji;
  • identyfikator (opcjonalny): odpowiada domenie lub subdomenie. Jeśli go nie podano, używana jest bieżąca domena.
  • ikonę (opcjonalnie).

pubKeyCredParams

Parametry danych uwierzytelniających klucza publicznego to lista dozwolonych algorytmów i typów kluczy. Ta lista musi zawierać co najmniej 1 element.

excludeCredentials

Użytkownik próbujący zarejestrować urządzenie mógł zarejestrować inne urządzenia. Aby ograniczyć tworzenie wielu danych logowania na potrzeby tego samego konta w ramach jednego modułu uwierzytelniającego, możesz zignorować te urządzenia. Element transports (jeśli został podany) powinien zawierać wynik wywołania funkcji getTransports() podczas rejestracji każdego dokumentu.

authenticatorSelection.authenticatorAttachment

wskazuje, czy urządzenie powinno być zamontowane na platformie i czy nie ma w tym zakresie wymagań. Ustaw wartość „platform”. Oznacza to, że chcemy mieć wbudowany moduł uwierzytelniający, a użytkownik nie będzie pytany o wstawienie np. klucz bezpieczeństwa USB.

residentKey

mają wartość „wymaganą”. aby utworzyć klucz dostępu.

Utwórz dane logowania

  1. Po utworzeniu klasy CreatePublicKeyCredentialRequest() musisz wywołać z utworzonym żądaniem wywołanie createCredential().

SignUpFragment.kt

//TODO call createCredential() with createPublicKeyCredentialRequest

try {
   response = credentialManager.createCredential(
       requireActivity(),
       request
   ) as CreatePublicKeyCredentialResponse
} catch (e: CreateCredentialException) {
   configureProgress(View.INVISIBLE)
   handlePasskeyFailure(e)
}
  • Musisz przekazać wymagane informacje, aby createCredential().
  • Gdy żądanie zostanie zrealizowane, na ekranie pojawi się dolna karta z prośbą o utworzenie klucza dostępu.
  • Teraz użytkownicy mogą potwierdzać swoją tożsamość za pomocą biometrii, blokady ekranu itp.
  • To Ty zajmujesz się widocznością renderowanych widoków i obsługujesz wyjątki, jeśli żądanie z jakiegoś powodu się nie powiedzie lub nie powiedzie się. W tym miejscu komunikaty o błędach są rejestrowane i wyświetlane w aplikacji w oknie dialogowym błędu. Pełne logi błędów możesz sprawdzić za pomocą Android Studio lub polecenia debugowania adb.

93022cb87c00f1fc.png

  1. Teraz należy zakończyć proces rejestracji, wysyłając dane uwierzytelniające klucza publicznego do serwera i wpuszczając użytkownika. Aplikacja odbiera obiekt danych logowania zawierający klucz publiczny, który można wysłać na serwer, aby zarejestrować klucz dostępu.

W tym przypadku użyliśmy pozorowanego serwera, więc zwracamy wartość „true” (prawda), wskazując, że serwer zapisał zarejestrowany klucz publiczny na potrzeby uwierzytelniania i weryfikacji w przyszłości.

W metodzie signUpWithPasskeys() znajdź odpowiedni komentarz i zastąp go następującym kodem:

SignUpFragment.kt

//TODO : complete the registration process after sending public key credential to your server and let the user in

data?.let {
   registerResponse()
   DataProvider.setSignedInThroughPasskeys(true)
   listener.showHome()
}
  • recordResponse zwracający wartość „true” oznacza, że serwer (pozorny) zapisał klucz publiczny do wykorzystania w przyszłości.
  • Flaga setSignedInThroughPasskeys ustawiona na wartość true wskazuje, że logujesz się za pomocą kluczy dostępu.
  • Po zalogowaniu się użytkownik zostanie przekierowany na ekran główny.

Następujący fragment kodu zawiera przykładowe opcje, które należy uzyskać:

{
  "id": String,
  "rawId": String,
  "type": "public-key",
  "response": {
    "clientDataJSON": String,
    "attestationObject": String,
  }
}

Ta tabela nie jest wyczerpująca, ale zawiera ważne parametry z sekcji PublicKeyCredential:

Parametry

Teksty reklam

id

Zakodowany w Base64URL identyfikator utworzonego klucza dostępu. Ten identyfikator pomaga przeglądarce określić, czy podczas uwierzytelniania na urządzeniu znajduje się pasujący klucz dostępu. Ta wartość musi być przechowywana w bazie danych w backendzie.

rawId

Wersja obiektu identyfikatora danych logowania w ArrayBuffer.

response.clientDataJSON

Dane klienta zakodowane w obiekcie ArrayBuffer.

response.attestationObject

Obiekt atestu zakodowanego w języku ArrayBuffer. Zawiera on ważne informacje, takie jak identyfikator RP, flagi i klucz publiczny.

Po uruchomieniu aplikacji możesz kliknąć przycisk Zarejestruj się za pomocą kluczy dostępu i utworzyć klucz.

4. Zapisz hasło u dostawcy danych uwierzytelniających

W tej aplikacji na ekranie rejestracji masz już zaimplementowane konto z nazwą użytkownika i hasłem do celów demonstracyjnych.

Aby zapisać dane logowania do hasła użytkownika u dostawcy haseł, wdrożysz funkcję CreatePasswordRequest w celu zapisania hasła w ramach metody createCredential().

  • Znajdź metodę signUpWithPassword() zamiennie na wywoływanie funkcji TODO createPassword :

SignUpFragment.kt

//TODO : Save the user credential password with their password provider

createPassword()
  • W metodzie createPassword() musisz utworzyć takie żądanie dotyczące hasła, a pole TODO należy zastąpić tym kodem :

SignUpFragment.kt

//TODO : CreatePasswordRequest with entered username and password

val request = CreatePasswordRequest(
   binding.username.text.toString(),
   binding.password.text.toString()
)
  • Następnie w metodzie createPassword() musisz utworzyć dane logowania, korzystając z funkcji tworzenia żądania hasła, i zapisać dane logowania użytkownika dotyczące hasła u dostawcy hasła, zastępując pozycję TODO następującym kodem :

SignUpFragment.kt

//TODO : Create credential with created password request


try {
   credentialManager.createCredential(request, requireActivity()) as CreatePasswordResponse
} catch (e: Exception) {
   Log.e("Auth", " Exception Message : " + e.message)
}
  • Udało Ci się zapisać dane logowania u dostawcy hasła użytkownika, aby uwierzytelniać za pomocą hasła jednym kliknięciem.

5. Dodaj możliwość uwierzytelniania za pomocą klucza dostępu lub hasła

Teraz możesz go używać do bezpiecznego uwierzytelniania w aplikacji.

629001f4a778d4fb.png

Uzyskaj test zabezpieczający i inne opcje przekazania do wywołania getPasskey()

Zanim poprosisz użytkownika o uwierzytelnienie, musisz zażądać parametrów przekazywanych z serwera w postaci kodu json WebAuthn, w tym testu zabezpieczającego.

Masz już w swoich zasobach przykładową odpowiedź(AuthFromServer.txt), która zwraca takie parametry w tym ćwiczeniu w Codelabs.

  • W aplikacji przejdź do pliku SignInFragment.kt, znajdź metodę signInWithSavedCredentials, w której wpiszesz logikę uwierzytelniania za pomocą zapisanego klucza dostępu lub hasła i pozwolisz użytkownikowi na :
  • Zaznacz blok Other z komentarzem, aby wywołać funkcję createPasskey() i zastąp ją następującym kodem :

SignInFragment.kt

//TODO : Call getSavedCredentials() method to signin using passkey/password

val data = getSavedCredentials()
  • W metodzie getSavedCredentials() musisz utworzyć funkcję GetPublicKeyCredentialOption() z niezbędnymi parametrami wymaganymi do uzyskania danych logowania od dostawcy danych logowania.

SigninFragment.kt

//TODO create a GetPublicKeyCredentialOption() with necessary registration json from server

val getPublicKeyCredentialOption =
   GetPublicKeyCredentialOption(fetchAuthJsonFromServer(), null)

Jest to metoda, która odczytuje z zasobów odpowiedź JSON uwierzytelniania i zwraca plik JSON uwierzytelniania, aby pobrać wszystkie klucze dostępu powiązane z tym kontem użytkownika.

Drugi parametr : clientDataHash – hasz używany do weryfikacji tożsamości jednostki uzależnionej, ustawiany tylko w przypadku ustawienia metody GetCredentialRequest.origin. W przypadku przykładowej aplikacji wartość null.

Trzeci parametr ma wartość true (prawda), jeśli wolisz, aby operacja zwracała natychmiast, gdy nie ma dostępnych danych logowania, zamiast cofać się do wykrywania zdalnych danych uwierzytelniających. W przeciwnym razie ma wartość „false” (fałsz).

  • Znajdź metodę downloadAuthJsonFromServer() i zastąp funkcję TODO poniższym kodem, aby zwrócić kod json, a także usunąć instrukcję zwracającą pusty ciąg znaków :

SignInFragment.kt

//TODO fetch authentication mock json

return requireContext().readFromAsset("AuthFromServer")

Uwaga : serwer tego ćwiczenia w Codelabs został zaprojektowany do zwracania kodu JSON, który jest jak najbardziej podobny do słownika PublicKeyCredentialRequestOptions przekazywanego do wywołania getCredential() interfejsu API. Poniżej znajduje się fragment kodu, który zawiera kilka przykładowych opcji, które powinny zostać wyświetlone:

{
  "challenge": String,
  "rpId": String,
  "userVerification": "",
  "timeout": 1800000
}

Poniższa tabela nie jest wyczerpująca, ale zawiera ważne parametry w słowniku PublicKeyCredentialRequestOptions:

Parametry

Teksty reklam

challenge

Wyzwanie wygenerowane przez serwer w obiekcie ArrayBuffer. Jest to wymagane, aby zapobiec atakom typu replay. Nigdy nie akceptuj tego samego wyzwania w odpowiedzi dwa razy. Powinien to być token CSRF.

rpId

Identyfikator RP to domena. Witryna może mieć domenę lub sufiks możliwy do zarejestrowania. Ta wartość musi być zgodna z parametrem rp.id używanym podczas tworzenia klucza dostępu.

  • Następnie musisz utworzyć obiektPasswordOption(), aby pobierać wszystkie zapisane hasła zapisane u dostawcy haseł przez interfejs Credential Manager API dla tego konta użytkownika. W metodzie getSavedCredentials() znajdź funkcję TODO i zastąp ją następującym :

SigninFragment.kt

//TODO create a PasswordOption to retrieve all the associated user's password

val getPasswordOption = GetPasswordOption()

Uzyskaj dane logowania

  • Następnie musisz wywołać żądanie getCredential() ze wszystkimi powyższymi opcjami, aby pobrać powiązane dane logowania :

SignInFragment.kt

//TODO call getCredential() with required credential options

val result = try {
   credentialManager.getCredential(
       requireActivity(),
       GetCredentialRequest(
           listOf(
               getPublicKeyCredentialOption,
               getPasswordOption
           )  
     )
   )
} catch (e: Exception) {
   configureViews(View.INVISIBLE, true)
   Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
   activity?.showErrorAlert(
       "An error occurred while authenticating through saved credentials. Check logs for additional details"
   )
   return null
}

if (result.credential is PublicKeyCredential) {
   val cred = result.credential as PublicKeyCredential
   DataProvider.setSignedInThroughPasskeys(true)
   return "Passkey: ${cred.authenticationResponseJson}"
}
if (result.credential is PasswordCredential) {
   val cred = result.credential as PasswordCredential
   DataProvider.setSignedInThroughPasskeys(false)
   return "Got Password - User:${cred.id} Password: ${cred.password}"
}
if (result.credential is CustomCredential) {
   //If you are also using any external sign-in libraries, parse them here with the utility functions provided.
}

  • Musisz przekazać wymagane informacje, aby uzyskać dane logowania getCredential(). Spowoduje to wyrenderowanie opcji na dole strony na podstawie listy opcji danych logowania i kontekstu aktywności w danym kontekście.
  • Gdy żądanie zostanie zrealizowane, na ekranie pojawi się dolna karta z listą wszystkich utworzonych danych logowania dla powiązanego konta.
  • Teraz użytkownicy mogą potwierdzać swoją tożsamość za pomocą biometrii, blokady ekranu itp., aby uwierzytelniać wybrane dane logowania.
  • Flaga setSignedInThroughPasskeys ustawiona na wartość true wskazuje, że logujesz się za pomocą kluczy dostępu. W przeciwnym razie ma wartość fałsz.
  • To Ty zajmujesz się widocznością renderowanych widoków i obsługujesz wyjątki, jeśli żądanie z jakiegoś powodu się nie powiedzie lub nie powiedzie się. W tym miejscu komunikaty o błędach są rejestrowane i wyświetlane w aplikacji w oknie dialogowym błędu. Pełne logi błędów możesz sprawdzić za pomocą Android Studio lub polecenia debugowania adb.
  • Teraz należy zakończyć proces rejestracji, wysyłając dane uwierzytelniające klucza publicznego do serwera i wpuszczając użytkownika. Aplikacja odbiera obiekt danych logowania zawierający klucz publiczny, który można wysłać na serwer w celu uwierzytelnienia za pomocą klucza dostępu.

W tym przypadku użyliśmy pozorowanego serwera, więc zwracamy po prostu wartość „prawda”, wskazując, że serwer zweryfikował klucz publiczny.

W metodzie signInWithSavedCredentials() znajdź odpowiedni komentarz i zastąp go następującym kodem:

SignInFragment.kt

//TODO : complete the authentication process after validating the public key credential to your server and let the user in.

data?.let {
   sendSignInResponseToServer()
   listener.showHome()
}
  • SendSigninResponseToServer() zwraca wartość „true” (prawda), wskazując, że serwer (przykładowy) zweryfikował klucz publiczny do wykorzystania w przyszłości.
  • Po zalogowaniu się użytkownik zostanie przekierowany na ekran główny.

Ten fragment kodu zawiera przykładowy obiekt PublicKeyCredential:

{
  "id": String
  "rawId": String
  "type": "public-key",
  "response": {
    "clientDataJSON": String
    "authenticatorData": String
    "signature": String
    "userHandle": String
  }
}

Ta tabela nie jest wyczerpująca, ale zawiera ważne parametry w obiekcie PublicKeyCredential:

Parametry

Teksty reklam

id

Zakodowany w Base64URL identyfikator uwierzytelnionego klucza dostępu.

rawId

Wersja obiektu identyfikatora danych logowania w ArrayBuffer.

response.clientDataJSON

Obiekt ArrayBuffer danych klienta. To pole zawiera informacje takie jak wyzwanie i pochodzenie, które serwer RP musi zweryfikować.

response.authenticatorData

Obiekt ArrayBuffer danych uwierzytelniających. To pole zawiera takie informacje jak identyfikator RP.

response.signature

Obiekt ArrayBuffer podpisu. Ta wartość stanowi rdzeń danych logowania i musi zostać zweryfikowana na serwerze.

response.userHandle

Obiekt ArrayBuffer zawierający identyfikator użytkownika ustawiony w momencie tworzenia. Tej wartości można użyć zamiast identyfikatora danych logowania, jeśli serwer musi wybrać używane wartości identyfikatorów lub jeśli backend chce uniknąć tworzenia indeksu dla identyfikatorów danych logowania.

Uruchom aplikację i zaloguj się -> Zaloguj się za pomocą kluczy dostępu lub zapisanego hasła i spróbuj zalogować się przy użyciu zapisanych danych logowania.

Wypróbuj

W aplikacji na Androida udało Ci się wdrożyć tworzenie kluczy dostępu, zapisywanie haseł w Menedżerze danych logowania oraz uwierzytelnianie za pomocą kluczy dostępu lub zapisanych haseł za pomocą interfejsu Credential Manager API.

6. Gratulacje!

Ćwiczenie z programowania ukończone. Ostateczną wersję rozwiązania znajdziesz na stronie https://github.com/android/identity-samples/tree/main/CredentialManager.

Jeśli masz pytania, zadaj je na StackOverflow z tagiem passkey.

Więcej informacji