Utwórz klucz dostępu

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.

Klucze dostępu są przechowywane u dostawcy danych logowania, a klucze publiczne – na serwerze aplikacji.
Rysunek 1. Tworzenie kluczy dostępu

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.

  1. Dodaj zależności do aplikacji: dodaj wymagane biblioteki Menedżera danych logowania.
  2. Utwórz instancję Credential Manager: utwórz instancję Credential Manager.
  3. 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 challenge i inne pola.
  4. 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 metody credentialManager.getCredential() w celu utworzenia klucza dostępu.
  5. 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.
  6. Zweryfikuj i zapisz klucz publiczny na serwerze: wykonaj czynności po stronie serwera, aby zweryfikować pochodzenie danych logowania, a następnie zapisz klucz publiczny.
  7. 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 pola Boolean na true.
      • residentKey: aby utworzyć klucz dostępu, ustaw wartość na required.
      • 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 w userVerificationszczegół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ść na true i 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 i CreateCredentialNoCreateOptionException w 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 to false. Jeśli ustawisz tę opcję na true, 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 wersji androidx.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:

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

  2. 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('=', ''))
    
  3. 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 (FillDialogSaveDialog) 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