Logowanie użytkownika za pomocą Menedżera danych logowania

Credential Manager to interfejs API Jetpack, który obsługuje wielokrotne logowanie takie jak nazwa użytkownika i hasło, klucze dostępu i logowanie sfederowane (np. Zaloguj się przez Google) za pomocą jednego interfejsu API, dla programistów.

Ponadto Credential Manager ujednolica interfejs logowania niezależnie od metody uwierzytelniania, dzięki czemu użytkownicy mogą łatwiej i w bardziej przejrzysty sposób logować się w aplikacjach niezależnie od wybranej metody.

Na tej stronie wyjaśniamy pojęcie kluczy dostępu i jak zaimplementować obsługę po stronie klienta dla rozwiązań uwierzytelniania, w tym kluczy dostępu, za pomocą interfejsu Credential Manager API. Dostępna jest też osobna strona z najczęstszymi pytaniami, na której znajdziesz odpowiedzi na bardziej szczegółowe, szczegółowe pytania.

Twoja opinia ma duże znaczenie dla ulepszania interfejsu Credential Manager API. Udostępnij wszelkie znalezione problemy lub pomysły dotyczące ulepszenia interfejsu API, klikając ten link:

Przesyłanie opinii

Informacje o kluczach dostępu

Klucze dostępu są bezpieczniejsze i łatwiejsze w zastępowaniu haseł. Dzięki kluczom dostępu użytkownicy mogą logować się w aplikacjach i na stronach internetowych za pomocą czujnika biometrycznego (np. odcisku palca lub rozpoznawania twarzy), kodu PIN lub wzoru. Zapewnia to płynne logowania się, dzięki czemu użytkownicy nie muszą zapamiętywać nazw użytkowników ani haseł.

Klucze dostępu bazują na WebAuthn (Web Authentication), standardie opracowanym wspólnie przez FIDO Alliance oraz World Wide Web Consortium (W3C). WebAuthn używa szyfrowania kluczem publicznym do uwierzytelniania użytkownika. Witryna lub aplikacja, do której użytkownik może zobaczyć i zapisać klucz publiczny, ale nigdy prywatny . Klucz prywatny jest przechowywany w prywatności i w bezpiecznym miejscu. Ponieważ klucz jest unikalny i powiązany z witryną lub aplikacją, nie można go przechwycić, co zwiększa bezpieczeństwo.

Menedżer danych logowania umożliwia użytkownikom tworzenie kluczy dostępu i przechowywanie ich w Menedżerze haseł Google.

Wskazówki dotyczące wdrażania znajdziesz w artykule Uwierzytelnianie użytkowników za pomocą kluczy dostępu. i umożliwia bezproblemowe uwierzytelnianie przy użyciu klucza dostępu za pomocą usługi Credential Manager.

Wymagania wstępne

Aby używać usługi Credential Manager, wykonaj czynności opisane w tej sekcji.

Używanie najnowszej wersji platformy

Menedżer danych logowania jest obsługiwany na Androidzie 4.4 (poziom interfejsu API 19) i nowszych.

Dodaj zależności do aplikacji

Dodaj te zależności do skryptu kompilacji modułu aplikacji:

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-alpha05")

    // optional - needed for credentials support from play services, for devices running
    // Android 13 and below.
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-alpha05")
}

Odlotowe

dependencies {
    implementation "androidx.credentials:credentials:1.5.0-alpha05"

    // optional - needed for credentials support from play services, for devices running
    // Android 13 and below.
    implementation "androidx.credentials:credentials-play-services-auth:1.5.0-alpha05"
}

Zachowanie klas w pliku ProGuard

W pliku proguard-rules.pro modułu dodaj te dyrektywy:

-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
  *;
}

Dowiedz się więcej o skompresowaniu, zaciemnianiu i optymalizowaniu aplikacji.

Dodanie obsługi Digital Asset Links

Aby włączyć obsługę kluczy dostępu w aplikacji na Androida, powiązać ją z witryną, której jest właścicielem. Możesz zadeklarować to powiązanie, wypełniając następujące kroki:

  1. Utwórz plik JSON protokołu Digital Asset Links. Aby na przykład zadeklarować, że strona https://signin.example.com i aplikacja na Androida z pakietem nazwa com.example może współdzielić dane logowania, utworzyć plik o nazwie assetlinks.json z tą treścią:

    [
      {
        "relation" : [
          "delegate_permission/common.handle_all_urls",
          "delegate_permission/common.get_login_creds"
        ],
        "target" : {
          "namespace" : "android_app",
          "package_name" : "com.example.android",
          "sha256_cert_fingerprints" : [
            SHA_HEX_VALUE
          ]
        }
      }
    ]
    

    Pole relation jest tablicą jednego lub większej liczby ciągów tekstowych opisujących relacji. Deklarowanie, że aplikacje i witryny korzystają z tego samego loginu dane logowania, określ relacje jako delegate_permission/handle_all_urls i delegate_permission/common.get_login_creds

    Pole target to obiekt określający zasób, którego dotyczy deklaracja. Te pola identyfikują witrynę:

    namespace web
    site

    Adres URL witryny w formacie https://domain[:optional_port], na przykład https://www.example.com.

    domain musi być w pełni kwalifikowany. Wartość optional_port należy pominąć, jeśli używasz portu 443 w HTTPS.

    Elementem docelowym site może być tylko domena główna: nie można by ograniczyć powiązanie aplikacji do konkretnego podkatalogu. Nie umieszczaj w adresie URL ścieżki, np. ukośnika na końcu.

    Subdomeny nie są uważane za dopasowanie: jeśli podasz domain jako www.example.com, domena www.counter.example.com nie będzie powiązana z Twoją aplikacją.

    Te pola identyfikują aplikację na Androida:

    namespace android_app
    package_name Nazwa pakietu zadeklarowana w pliku manifestu aplikacji. Przykład: com.example.android
    sha256_cert_fingerprints Odciski cyfrowe SHA-256 certyfikatu podpisywania aplikacji.
  2. Umieść plik JSON protokołu Digital Asset Links w tej lokalizacji w domenie logowania:

    https://domain[:optional_port]/.well-known/assetlinks.json
    

    Jeśli na przykład Twoja domena logowania to signin.example.com, umieść plik JSON pod adresem https://signin.example.com/.well-known/assetlinks.json.

    Typ MIME pliku Digital Asset Link musi być JSON. Upewnij się, że serwer wysyła nagłówek Content-Type: application/json w odpowiedzi.

  3. Upewnij się, że Twój dostawca hostingu pozwala Google na pobranie Twojego linku do zasobu cyfrowego . Jeśli masz plik robots.txt, musi on zezwalać agentowi Googlebot na pobieranie informacji z pliku /.well-known/assetlinks.json. Większość witryn może zezwolić dowolnemu automatycznemu agentowi na pobieranie plików z ścieżki /.well-known/, aby inne usługi mogły uzyskać dostęp do metadanych w tych plikach:

    User-agent: *
    Allow: /.well-known/
    
  4. Dodaj ten wiersz do pliku manifestu w <application>:

    <meta-data android:name="asset_statements" android:resource="@string/asset_statements" />
    
  5. Jeśli logujesz się za pomocą hasła w Menedżerze danych logowania, wykonaj te czynności, aby skonfigurować w pliku manifestu linkowanie zasobów cyfrowych. Ten krok nie jest wymagane, jeśli używasz tylko kluczy dostępu.

    Zadeklaruj powiązanie w aplikacji na Androida. Dodaj obiekt, który określa Pliki (assetlinks.json) do wczytania. Musisz uciec od wszelkich apostrofów cudzysłowów używanych w ciągu znaków. Na przykład:

    <string name="asset_statements" translatable="false">
    [{
      \"include\": \"https://signin.example.com/.well-known/assetlinks.json\"
    }]
    </string>
    
    > GET /.well-known/assetlinks.json HTTP/1.1
    > User-Agent: curl/7.35.0
    > Host: signin.example.com
    
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    

Konfigurowanie usługi Credential Manager

Aby skonfigurować i zainicjować obiekt CredentialManager, dodaj logikę podobną do tej:

Kotlin

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
val credentialManager = CredentialManager.create(context)

Java

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
CredentialManager credentialManager = CredentialManager.create(context)

Wskazać pola danych logowania

W Androidzie 14 i nowszych można używać atrybutu isCredential do wskazywania pól danych logowania, takich jak pola nazwy użytkownika lub hasła. Ten atrybut wskazuje, że ten widok jest polem danych logowania, które jest przeznaczone do pracy Menedżer danych logowania i zewnętrzni dostawcy danych uwierzytelniających pomagający w uzupełnianiu danych uwierzytelniających lepsze sugestie autouzupełniania. Gdy aplikacja używa danych logowania API Manager, planszę dolną z dostępnymi danymi uwierzytelniającymi Menedżera danych logowania nie ma już potrzeby pokazywania okna autouzupełniania dla nazwa użytkownika lub hasło. I analogicznie, nie będzie trzeba podawać okno zapisywania haseł, ponieważ aplikacja będzie żądać interfejsu Credential Manager API aby zapisać dane logowania.

Aby używać atrybutu isCredential, dodaj go do odpowiednich widoków:

<TextView
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:isCredential="true"
...
 />

Logowanie użytkownika

Aby pobrać wszystkie opcje kluczy dostępu i haseł powiązane z kontem użytkownika:

  1. Zainicjuj opcje uwierzytelniania hasła i klucza dostępu:

    Kotlin

    // Retrieves the user's saved password for your app from their
    // password provider.
    val getPasswordOption = GetPasswordOption()
    
    // Get passkey from the user's public key credential provider.
    val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
        requestJson = requestJson
    )

    Java

    // Retrieves the user's saved password for your app from their
    // password provider.
    GetPasswordOption getPasswordOption = new GetPasswordOption();
    
    // Get passkey from the user's public key credential provider.
    GetPublicKeyCredentialOption getPublicKeyCredentialOption =
            new GetPublicKeyCredentialOption(requestJson);
  2. Korzystając z opcji pobranych w poprzednim kroku, utwórz żądania zalogowania się.

    Kotlin

    val getCredRequest = GetCredentialRequest(
        listOf(getPasswordOption, getPublicKeyCredentialOption)
    )

    Java

    GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder()
        .addCredentialOption(getPasswordOption)
        .addCredentialOption(getPublicKeyCredentialOption)
        .build();
  3. Uruchom proces logowania:

    Kotlin

    coroutineScope.launch {
        try {
            val result = credentialManager.getCredential(
                // Use an activity-based context to avoid undefined system UI
                // launching behavior.
                context = activityContext,
                request = getCredRequest
            )
            handleSignIn(result)
        } catch (e : GetCredentialException) {
            handleFailure(e)
        }
    }
    
    fun handleSignIn(result: GetCredentialResponse) {
        // Handle the successfully returned credential.
        val credential = result.credential
    
        when (credential) {
            is PublicKeyCredential -> {
                val responseJson = credential.authenticationResponseJson
                // Share responseJson i.e. a GetCredentialResponse on your server to
                // validate and  authenticate
            }
            is PasswordCredential -> {
                val username = credential.id
                val password = credential.password
                // Use id and password to send to your server to validate
                // and authenticate
            }
          is CustomCredential -> {
              // If you are also using any external sign-in libraries, parse them
              // here with the utility functions provided.
              if (credential.type == ExampleCustomCredential.TYPE)  {
              try {
                  val ExampleCustomCredential = ExampleCustomCredential.createFrom(credential.data)
                  // Extract the required credentials and complete the authentication as per
                  // the federated sign in or any external sign in library flow
                  } catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
                      // Unlikely to happen. If it does, you likely need to update the dependency
                      // version of your external sign-in library.
                      Log.e(TAG, "Failed to parse an ExampleCustomCredential", e)
                  }
              } else {
                // Catch any unrecognized custom credential type here.
                Log.e(TAG, "Unexpected type of credential")
              }
            } else -> {
                // Catch any unrecognized credential type here.
                Log.e(TAG, "Unexpected type of credential")
            }
        }
    }

    Java

    credentialManager.getCredentialAsync(
        // Use activity based context to avoid undefined
        // system UI launching behavior
        activity,
        getCredRequest,
        cancellationSignal,
        <executor>,
        new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
            @Override
            public void onResult(GetCredentialResponse result) {
                handleSignIn(result);
            }
    
            @Override
            public void onError(GetCredentialException e) {
                handleFailure(e);
            }
        }
    );
    
    public void handleSignIn(GetCredentialResponse result) {
        // Handle the successfully returned credential.
        Credential credential = result.getCredential();
        if (credential instanceof PublicKeyCredential) {
            String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson();
            // Share responseJson i.e. a GetCredentialResponse on your server to validate and authenticate
        } else if (credential instanceof PasswordCredential) {
            String username = ((PasswordCredential) credential).getId();
            String password = ((PasswordCredential) credential).getPassword();
            // Use id and password to send to your server to validate and authenticate
        } else if (credential instanceof CustomCredential) {
            if (ExampleCustomCredential.TYPE.equals(credential.getType())) {
                try {
                    ExampleCustomCredential customCred = ExampleCustomCredential.createFrom(customCredential.getData());
                    // Extract the required credentials and complete the
                    // authentication as per the federated sign in or any external
                    // sign in library flow
                } catch (ExampleCustomCredential.ExampleCustomCredentialParsingException e) {
                    // Unlikely to happen. If it does, you likely need to update the
                    // dependency version of your external sign-in library.
                    Log.e(TAG, "Failed to parse an ExampleCustomCredential", e);
                }
            } else {
                // Catch any unrecognized custom credential type here.
                Log.e(TAG, "Unexpected type of credential");
            }
        } else {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential");
        }
    }

Z przykładu poniżej dowiesz się, jak sformatować żądanie JSON, gdy otrzymasz klucz dostępu:

{
  "challenge": "T1xCsnxM2DNL2KdK5CLa6fMhD7OBqho6syzInk_n-Uo",
  "allowCredentials": [],
  "timeout": 1800000,
  "userVerification": "required",
  "rpId": "credential-manager-app-test.glitch.me"
}

Poniższy przykład pokazuje, jak może wyglądać odpowiedź JSON po uzyskaniu danych logowania z kluczem publicznym:

{
  "id": "KEDetxZcUfinhVi6Za5nZQ",
  "type": "public-key",
  "rawId": "KEDetxZcUfinhVi6Za5nZQ",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVDF4Q3NueE0yRE5MMktkSzVDTGE2Zk1oRDdPQnFobzZzeXpJbmtfbi1VbyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
    "authenticatorData": "j5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGQdAAAAAA",
    "signature": "MEUCIQCO1Cm4SA2xiG5FdKDHCJorueiS04wCsqHhiRDbbgITYAIgMKMFirgC2SSFmxrh7z9PzUqr0bK1HZ6Zn8vZVhETnyQ",
    "userHandle": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0"
  }
}

Obsługa wyjątków, gdy dane logowania nie są dostępne

W niektórych przypadkach użytkownik może nie mieć żadnych danych uwierzytelniających lub nie wyrazić zgody na użycie dostępnych danych. Jeśli wywołana zostanie funkcja getCredential() i nie zostanie znaleziony żaden identyfikator, zwracany jest obiekt NoCredentialException. W takiej sytuacji Twój kod powinien obsłużyć NoCredentialExceptionprzypadki.

Kotlin

try {
  val credential = credentialManager.getCredential(credentialRequest)
} catch (e: NoCredentialException) {
  Log.e("CredentialManager", "No credential available", e)
}

Java

try {
  Credential credential = credentialManager.getCredential(credentialRequest);
} catch (NoCredentialException e) {
  Log.e("CredentialManager", "No credential available", e);
}

Na urządzeniu z Androidem 14 lub nowszym możesz skrócić czas oczekiwania na wyświetlenie konta za pomocą metody prepareGetCredential() przed wywołaniem funkcji getCredential()

Kotlin

val response = credentialManager.prepareGetCredential(
  GetCredentialRequest(
    listOf(
      <getPublicKeyCredentialOption>,
      <getPasswordOption>
    )
  )
}

Java

GetCredentialResponse response = credentialManager.prepareGetCredential(
  new GetCredentialRequest(
    Arrays.asList(
      new PublicKeyCredentialOption(),
      new PasswordOption()
    )
  )
);

Metoda prepareGetCredential() nie wywołuje elementów interfejsu. Pomaga tylko w przygotowaniu się do wykonania pozostałych operacji związanych z danymi logowania (które obejmują interfejsy użytkownika) za pomocą interfejsu API getCredential().

Dane z pamięci podręcznej są zwracane w obiekcie PrepareGetCredentialResponse. Jeśli Istnieją dane logowania, wyniki zostaną zapisane w pamięci podręcznej. później uruchomić pozostały interfejs API getCredential(), aby wyświetlić konto. z danymi z pamięci podręcznej.

Procesy rejestracji

Możesz zarejestrować użytkownika na potrzeby uwierzytelniania przy użyciu klucz dostępu lub hasło.

Utwórz klucz dostępu

Aby dać użytkownikom możliwość zarejestrowania klucza i używania go do ponownego uwierzytelniania: zarejestrować dane logowania użytkownika przy użyciu obiektu CreatePublicKeyCredentialRequest.

Kotlin

fun createPasskey(requestJson: String, preferImmediatelyAvailableCredentials: Boolean) {
    val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
        // Contains the request in JSON format. Uses the standard WebAuthn
        // web JSON spec.
        requestJson = requestJson,
        // Defines whether you prefer to use only immediately available
        // credentials, not hybrid credentials, to fulfill this request.
        // This value is false by default.
        preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
    )

    // Execute CreateCredentialRequest asynchronously to register credentials
    // for a user account. Handle success and failure cases with the result and
    // exceptions, respectively.
    coroutineScope.launch {
        try {
            val result = credentialManager.createCredential(
                // Use an activity-based context to avoid undefined system
                // UI launching behavior
                context = activityContext,
                request = createPublicKeyCredentialRequest,
            )
            handlePasskeyRegistrationResult(result)
        } catch (e : CreateCredentialException){
            handleFailure(e)
        }
    }
}

fun handleFailure(e: CreateCredentialException) {
    when (e) {
        is CreatePublicKeyCredentialDomException -> {
            // Handle the passkey DOM errors thrown according to the
            // WebAuthn spec.
            handlePasskeyError(e.domError)
        }
        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 CreateCredentialUnknownException -> ...
        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}")
    }
}

Java

public void createPasskey(String requestJson, boolean preferImmediatelyAvailableCredentials) {
    CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest =
            // `requestJson` contains the request in JSON format. Uses the standard
            // WebAuthn web JSON spec.
            // `preferImmediatelyAvailableCredentials` defines whether you prefer
            // to only use immediately available credentials, not  hybrid credentials,
            // to fulfill this request. This value is false by default.
            new CreatePublicKeyCredentialRequest(
                requestJson, preferImmediatelyAvailableCredentials);

    // Execute CreateCredentialRequest asynchronously to register credentials
    // for a user account. Handle success and failure cases with the result and
    // exceptions, respectively.
    credentialManager.createCredentialAsync(
        // Use an activity-based context to avoid undefined system
        // UI launching behavior
        requireActivity(),
        createPublicKeyCredentialRequest,
        cancellationSignal,
        executor,
        new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
            @Override
            public void onResult(CreateCredentialResponse result) {
                handleSuccessfulCreatePasskeyResult(result);
            }

            @Override
            public void onError(CreateCredentialException e) {
                if (e instanceof CreatePublicKeyCredentialDomException) {
                    // Handle the passkey DOM errors thrown according to the
                    // WebAuthn spec.
                    handlePasskeyError(((CreatePublicKeyCredentialDomException)e).getDomError());
                } else if (e instanceof CreateCredentialCancellationException) {
                    // The user intentionally canceled the operation and chose not
                    // to register the credential.
                } else if (e instanceof CreateCredentialInterruptedException) {
                    // Retry-able error. Consider retrying the call.
                } else if (e instanceof CreateCredentialProviderConfigurationException) {
                    // Your app is missing the provider configuration dependency.
                    // Most likely, you're missing the
                    // "credentials-play-services-auth" module.
                } else if (e instanceof CreateCredentialUnknownException) {
                } else if (e instanceof 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.getClass().getName());
                }
            }
        }
    );
}

Formatowanie żądania JSON

Po utworzeniu klucza dostępu musisz powiązać go z kontem użytkownika i zapisać klucz publiczny klucza na serwerze. Oto przykładowy kod jak sformatować żądanie JSON podczas tworzenia klucza dostępu.

W tym poście na blogu o wprowadzaniu płynnego uwierzytelniania w aplikacjach znajdziesz informacje o sformatowaniu żądania JSON podczas tworzenia kluczy dostępu i uwierzytelniania za ich pomocą. Dowiesz się też, dlaczego hasła nie są skutecznym rozwiązaniem uwierzytelniania, jak wykorzystać istniejące dane biometryczne, jak powiązać aplikację z witryną, jak tworzyć klucze dostępu i jak uwierzytelniać się za ich pomocą.

{
  "challenge": "abc123",
  "rp": {
    "name": "Credential Manager example",
    "id": "credential-manager-test.example.com"
  },
  "user": {
    "id": "def456",
    "name": "helloandroid@gmail.com",
    "displayName": "helloandroid@gmail.com"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [
    {"id": "ghi789", "type": "public-key"},
    {"id": "jkl012", "type": "public-key"}
  ],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

Ustaw wartości dla authenticatorAttachment

Parametr authenticatorAttachment można ustawić tylko podczas tworzenia danych logowania. Możesz podać wartość platform, cross-platform lub nie podać żadnej wartości. W większości przypadków zalecana jest wartość 0.

  • platform: aby zarejestrować aktualne urządzenie użytkownika lub poprosić użytkownika o przejście na klucze dostępu po zalogowaniu się, ustaw wartość authenticatorAttachment na platform.
  • cross-platform: ta wartość jest często używana podczas rejestrowania danych logowania wieloskładnikowych i nie jest używana w kontekście klucza dostępu.
  • Brak wartości: aby zapewnić użytkownikom elastyczność tworzenia. kluczy dostępu na preferowanych urządzeniach (np. w ustawieniach konta), Parametr authenticatorAttachment nie powinien być określony, gdy użytkownik wybierze opcję aby dodać klucz dostępu. W większości przypadków najlepszym rozwiązaniem jest pozostawienie parametru bez określenia.

zapobieganie tworzeniu powielonych kluczy dostępu.

Wyświetl identyfikatory danych logowania w opcjonalnej tablicy excludeCredentials, aby zapobiec tworzenie nowego klucza dostępu, jeśli istnieje już taki sam klucz dostępu dostawcy usług.

Obsługa odpowiedzi JSON

Ten fragment kodu przedstawia przykładową odpowiedź JSON dotyczącą utworzenia danych logowania z kluczem publicznym. Dowiedz się więcej o obsłudze zwróconego klucza publicznego danych logowania.

{
  "id": "KEDetxZcUfinhVi6Za5nZQ",
  "type": "public-key",
  "rawId": "KEDetxZcUfinhVi6Za5nZQ",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibmhrUVhmRTU5SmI5N1Z5eU5Ka3ZEaVh1Y01Fdmx0ZHV2Y3JEbUdyT0RIWSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
    "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A"
  }
}

Zweryfikuj źródło na podstawie pliku JSON z danymi klienta

origin reprezentuje aplikację lub witrynę, do której pochodzi z żądania i jest używane przez klucze dostępu do ochrony przed atakami phishingowymi. Serwer aplikacji jest wymagany do sprawdzenia klienta źródła danych do listy dozwolonych zatwierdzonych aplikacji i witryn. Jeśli serwer otrzymuje żądanie od aplikacji lub witryny z nierozpoznanego źródła, należy odrzucić.

W przypadku witryny internetowej origin odzwierciedla to samo pochodzenie witryny, gdzie dane logowania na konto Google. Na przykład dla adresu URL https://www.example.com:8443/store?category=shoes#athletic , origin to https://www.example.com:8443

W przypadku aplikacji na Androida user agent automatycznie ustawia origin na podpis aplikacji wywołującej. Ten podpis powinien zostać zweryfikowany jako dopasowanie na serwerze, aby zweryfikować wywołującego interfejs API klucza dostępu. Nazwa Androida origin to identyfikator URI utworzony na podstawie hasza SHA-256 certyfikatu podpisywania pliku APK, np.:

android:apk-key-hash:<sha256_hash-of-apk-signing-cert>

Skróty SHA-256 certyfikatów podpisywania z magazynu kluczy można znaleźć za pomocą uruchamiając w terminalu to polecenie:

keytool -list -keystore <path-to-apk-signing-keystore>

Identyfikatory SHA-256 są w formacie szesnastkowym rozdzielanym dwukropkiem (91:F7:CB:F9:D6:81…), a wartości origin w Androidzie są zakodowane w formacie base64url. Ten przykładowy skrypt w języku Python pokazuje, jak przekonwertować format hasha na zgodny format szesnastkowy rozdzielany dwukropkiem:

import binascii
import base64
fingerprint = '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5'
print("android:apk-key-hash:" + base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))

Zastąp wartość fingerprint własną wartością. Oto przykładowy wynik:

android:apk-key-hash:kffL-daBUxvHpY-4M8yhTavt5QnFEI2LsexohxrGPYU

Następnie możesz dopasować ten ciąg znaków jako dozwolone pochodzenie na serwerze. Jeśli wiele certyfikatów podpisywania, takich jak certyfikaty do debugowania i publikowania, lub wielu aplikacji, a następnie powtórz proces i zaakceptuj wszystkie te źródła jako prawidłowe. na serwerze.

Zapisywanie hasła użytkownika

Jeśli użytkownik poda nazwę użytkownika i hasło w ramach procesu uwierzytelniania w aplikacji, możesz zarejestrować dane logowania użytkownika, których można użyć do jego uwierzytelnienia. Aby to zrobić, utwórz obiekt CreatePasswordRequest:

Kotlin

fun registerPassword(username: String, password: String) {
    // Initialize a CreatePasswordRequest object.
    val createPasswordRequest =
            CreatePasswordRequest(id = username, password = password)

    // Create credential and handle result.
    coroutineScope.launch {
        try {
            val result =
                credentialManager.createCredential(
                    // Use an activity based context to avoid undefined
                    // system UI launching behavior.
                    activityContext,
                    createPasswordRequest
                  )
            handleRegisterPasswordResult(result)
        } catch (e: CreateCredentialException) {
            handleFailure(e)
        }
    }
}

Java

void registerPassword(String username, String password) {
    // Initialize a CreatePasswordRequest object.
    CreatePasswordRequest createPasswordRequest =
        new CreatePasswordRequest(username, password);

    // Register the username and password.
    credentialManager.createCredentialAsync(
        // Use an activity-based context to avoid undefined
        // system UI launching behavior
        requireActivity(),
        createPasswordRequest,
        cancellationSignal,
        executor,
        new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
            @Override
            public void onResult(CreateCredentialResponse result) {
                handleResult(result);
            }

            @Override
            public void onError(CreateCredentialException e) {
                handleFailure(e);
            }
        }
    );
}

Odzyskiwanie danych logowania do zespołu pomocy

Jeśli użytkownik nie ma już dostępu do urządzenia, na którym były przechowywane jego dane logowania, może być konieczne przywrócenie danych z bezpiecznej kopii zapasowej online. Aby dowiedzieć się więcej o tym, jak obsługiwać proces odzyskiwania danych logowania, przeczytaj sekcję „Odzyskiwanie dostępu lub dodawanie nowych urządzeń” w poście na blogu Bezpieczeństwo kluczy dostępu w menedżerze haseł Google.

Dodanie obsługi narzędzi do zarządzania hasłami za pomocą znanych adresów URL punktów końcowych kluczy dostępu

Aby zapewnić płynną integrację i przyszłą zgodność z narzędziami do zarządzania hasłami i danymi logowania, zalecamy dodanie obsługi znanych adresów URL punktów końcowych kluczy dostępu. Jest to otwarty protokół, który umożliwia stronom formalnie reklamowanie obsługi kluczy dostępu i zapewnia bezpośrednie linki do rejestracji i zarządzania kluczami dostępu.

  1. W przypadku strony https://example.com, która ma stronę internetową oraz aplikacje na Androida i iOS, znany adres URL to https://example.com/.well-known/passkey-endpoints.
  2. Gdy wysyła się zapytanie do adresu URL, odpowiedź powinna używać tego schematu

    {
      "enroll": "https://example.com/account/manage/passkeys/create"
      "manage": "https://example.com/account/manage/passkeys"
    }
    
  3. Aby link otwierał się bezpośrednio w aplikacji, a nie w przeglądarce, użyj linków do aplikacji na Androida.

  4. Więcej informacji można znaleźć w Wyjaśnienie dobrze znanego adresu URL punktów końcowych klucza dostępu na GitHubie.

Pomagaj użytkownikom zarządzać kluczami dostępu, pokazując, który dostawca je utworzył

Wyzwanie, jakie stoją przed użytkownikami podczas zarządzania wieloma kluczami dostępu powiązanymi z danym identyfikuje właściwy klucz dostępu do edycji lub usunięcia. Aby pomóc w rozwiązaniu tego problemu, zalecamy, aby aplikacje i witryny zawierały dodatkowe informacje, takie jak nazwa dostawcy, data utworzenia i data ostatniego użycia na liście kluczy dostępu na ekranie ustawień aplikacji. Informacje o dostawcy można uzyskać, analizując identyfikator AAGUID powiązany z odpowiednim kluczem dostępu. Identyfikator AAGUID można znaleźć w danych uwierzytelniania klucza dostępu.

Jeśli na przykład użytkownik utworzy klucz dostępu na urządzeniu z Androidem za pomocą Menedżer haseł Google otrzymuje następnie identyfikator AAGUID, który wygląda np.: „ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4”. Strona uzależniona może dodać adnotację do klucza dostępu na liście kluczy, aby wskazać, że został on utworzony przy użyciu Menedżer haseł Google.

Aby zmapować identyfikator AAGUID na dostawcę kluczy dostępu, RP mogą wykorzystywać pochodzące od społeczności z repozytorium identyfikatorów AAGUID. Wyszukaj identyfikator AAGUID na , aby znaleźć nazwę i ikonę dostawcy kluczy dostępu.

Dowiedz się więcej o integracji z AAGUID.

Rozwiązywanie typowych problemów

W tabeli poniżej znajdziesz kilka typowych kodów błędów wraz z ich opisami oraz informacje o ich przyczynach:

Kod i opis błędu Przyczyna
W przypadku niepowodzenia logowania: 16: Użytkownik został tymczasowo zablokowany z powodu zbyt wielu anulowanych próśb o logowanie.

Jeśli podczas tworzenia aplikacji natrafisz na 24-godzinny okres oczekiwania, możesz go zresetować, usuwając pamięć podręczną aplikacji Usługi Google Play.

Aby przełączyć ten okres oczekiwania na urządzeniu testowym lub emulatorze, otwórz do aplikacji Telefon i wpisz ten kod: *#*#66382723#*#* Aplikacja Dialer czyści wszystkie dane wejściowe i może się zamknąć, ale nie wyświetla komunikatu z potwierdzeniem.

Błąd przy rozpoczęciu logowania: 8. nieznany błąd wewnętrzny.
  1. Urządzenie nie jest prawidłowo skonfigurowane z kontem Google.
  2. Plik JSON klucza dostępu jest tworzony nieprawidłowo.
CreatePublicKeyCredentialDomException: The incoming request cannot be validated Identyfikator pakietu aplikacji nie jest zarejestrowany na Twoim serwerze. Zweryfikuj w integrację po stronie serwera.
CreateCredentialUnknownException: podczas zapisywania hasła znaleziono hasło odpowiedź dotycząca niepowodzenia jednym dotknięciem 16: pominięcie zapisywania hasła, ponieważ użytkownik prawdopodobnie pojawi się pytanie w przypadku autouzupełniania na urządzeniu z Androidem Ten błąd występuje tylko w Androidzie 13 i starszych oraz tylko wtedy, gdy Google jest dostawcą funkcji Autouzupełniania. W takim przypadku użytkownicy widzą przycisk zapisu z autouzupełniania, a hasło zostanie zapisane w haśle Google Menedżer. Pamiętaj, że dane logowania zapisane za pomocą autouzupełniania z Google są udostępniane w obu kierunkach interfejsowi Credential Manager API. Dlatego ten błąd można bezpiecznie zignorować.

Dodatkowe materiały

Aby dowiedzieć się więcej o interfejsie API Credential Manager i kluczach dostępu, wyświetl następujące zasoby: