Intégrer la création et la connexion avec une clé d'accès à un seul geste avec des invites biométriques

Sur Android 15, le Gestionnaire d'identifiants prend en charge un flux en un seul geste pour la création et la récupération d'identifiants. Dans ce flux, les informations des identifiants créés ou utilisés sont affichées directement dans l'invite biométrique, avec un point d'entrée vers d'autres options. Ce processus simplifié crée efficace et rationalisé de création et de récupération d'identifiants.

Conditions requises :

  • Les données biométriques ont été configurées sur l'appareil de l'utilisateur et celui-ci les autorise pour l'authentification dans les applications.
  • Pour les flux de connexion, cette fonctionnalité n'est activée que pour les comptes uniques, même si plusieurs identifiants (comme une clé d'accès et un mot de passe) sont disponibles pour ce compte.

Activer le verrouillage par appui unique sur les flux de création de clés d'accès

Les étapes de création de cette méthode correspondent au processus de création d'identifiants existant. Dans votre BeginCreatePublicKeyCredentialRequest, utilisez handleCreatePasskeyQuery() pour traiter la requête si elle concerne une clé d'accès.

is BeginCreatePublicKeyCredentialRequest -> {
  Log.i(TAG, "Request is passkey type")
  return handleCreatePasskeyQuery(request, passwordCount, passkeyCount)
}

Dans votre handleCreatePasskeyQuery(), incluez BiometricPromptData avec la classe CreateEntry:

val createEntry = CreateEntry(
  // Additional properties...
  biometricPromptData = BiometricPromptData(
    allowedAuthenticators = allowedAuthenticator
  )
)

Les fournisseurs d'identifiants doivent définir explicitement la propriété allowedAuthenticator dans l'instance BiometricPromptData. Si cette propriété n'est pas définie, la valeur par défaut est DEVICE_WEAK. Définissez la propriété cryptoObject facultative si nécessaire pour votre cas d'utilisation.

Activer le verrouillage par appui unique sur les flux de clés d'accès de connexion

Comme pour le flux de création de clés d'accès, la configuration existante pour la gestion de la connexion des utilisateurs sera suivie. Sous BeginGetPublicKeyCredentialOption, utilisez populatePasskeyData() pour collecter les informations pertinentes sur la requête d'authentification :

is BeginGetPublicKeyCredentialOption -> {
  // ... other logic

  populatePasskeyData(
    origin,
    option,
    responseBuilder,
    autoSelectEnabled,
    allowedAuthenticator
  )

  // ... other logic as needed
}

Comme pour CreateEntry, une instance BiometricPromptData est définie sur la PublicKeyCredentialEntry. Si ces variables ne sont pas définies explicitement, allowedAuthenticator est défini par défaut sur BIOMETRIC_WEAK.

PublicKeyCredentialEntry(
  // other properties...

  biometricPromptData = BiometricPromptData(
    allowedAuthenticators = allowedAuthenticator
  )
)

Gérer la sélection des entrées d'identifiants

Lorsque vous gérez la sélection de saisie des identifiants pour la création de clés d'accès ou la sélection de clés d'accès lors de la connexion, appelez PendingIntentHandler's retrieveProviderCreateCredentialRequest ou retrieveProviderGetCredentialRequest, selon le cas. Ils renvoient des objets qui contiennent les métadonnées nécessaires au fournisseur. Par exemple, lorsque vous gérez la sélection de la saisie de la clé d'accès, modifiez votre code comme indiqué :

val createRequest = PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
if (createRequest == null) {
  Log.i(TAG, "request is null")
  setUpFailureResponseAndFinish("Unable to extract request from intent")
  return
}
// Other logic...

val biometricPromptResult = createRequest.biometricPromptResult

// Add your logic based on what needs to be done
// after getting biometrics

if (createRequest.callingRequest is CreatePublicKeyCredentialRequest) {
  val publicKeyRequest: CreatePublicKeyCredentialRequest =
    createRequest.callingRequest as CreatePublicKeyCredentialRequest

  if (biometricPromptResult == null) {
    // Do your own authentication flow, if needed
  }
  else if (biometricPromptResult.isSuccessful) {
    createPasskey(
        publicKeyRequest.requestJson,
        createRequest.callingAppInfo,
        publicKeyRequest.clientDataHash,
        accountId
    )
  } else {
    val error = biometricPromptResult.authenitcationError
    // Process the error
}

  // Other logic...
}

Cet exemple contient des informations sur la réussite du flux biométrique. Il contient également d'autres informations sur les identifiants. Si le flux échoue, utilisez le code d'erreur sous biometricPromptResult.authenticationError pour prendre des décisions. Les codes d'erreur renvoyés dans biometricPromptResult.authenticationError.errorCode sont les mêmes que ceux définis dans la bibliothèque androidx.biometric, tels que androidx.biometric.BiometricPrompt.NO_SPACE, androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS, androidx.biometric.BiometricPrompt.ERROR_TIMEOUT, etc. La authenticationError contient également un message d'erreur associé au errorCode pouvant s'afficher sur une interface utilisateur.

De même, extrayez les métadonnées pendant retrieveProviderGetCredentialRequest. Vérifiez si votre flux biométrique est null. Si oui, configurez vos propres données biométriques pour vous authentifier. Cela ressemble à la manière dont l'opération get est instrumentée :

val getRequest =
    PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)

if (getRequest == null) {
  Log.i(TAG, "request is null")
  setUpFailureResponseAndFinish("Unable to extract request from intent")
  return
}

// Other logic...

val biometricPromptResult = getRequest.biometricPromptResult

// Add your logic based on what needs to be done
// after getting biometrics

if (biometricPromptResult == null)
{
  // Do your own authentication flow, if necessary
} else if (biometricPromptResult.isSuccessful) {

Log.i(TAG, "The response from the biometricPromptResult was ${biometricPromptResult.authenticationResult.authenticationType}")

validatePasskey(
    publicKeyRequest.requestJson,
    origin,
    packageName,
    uid,
    passkey.username,
    credId,
    privateKey
)
  } else {
    val error = biometricPromptResult.authenitcationError
    // Process the error
}

  // Other logic...