Integrar a criação de chaves de acesso com toque único e login com solicitações biométricas

No Android 15, o Gerenciador de credenciais oferece suporte a um único fluxo de toque para credenciais criação e recuperação. Nesse fluxo, as informações da credencial criada ou sendo usada é mostrada diretamente no comando biométrico, junto com um ponto de entrada para mais opções. Esse processo simplificado cria um processo de criação e recuperação de credenciais mais eficiente e simplificado.

Requisitos:

  • A biometria foi configurada no dispositivo do usuário, e ele permite a autenticação em aplicativos.
  • Para fluxos de login, esse recurso é ativado apenas para cenários de conta única, mesmo que haja várias credenciais (como chave de acesso e senha) disponíveis para essa conta.

Ativar o toque único em fluxos de criação de chaves de acesso

As etapas de criação desse método correspondem à criação de credenciais atual de análise de dados. No BeginCreatePublicKeyCredentialRequest, use handleCreatePasskeyQuery() para processar a solicitação se for para uma chave de acesso.

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

No handleCreatePasskeyQuery(), inclua BiometricPromptData com a classe CreateEntry:

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

Os provedores de credenciais precisam definir explicitamente a propriedade allowedAuthenticator. na instância BiometricPromptData. Se essa propriedade não for definida, o valor será DEVICE_WEAK por padrão. Defina a propriedade cryptoObject opcional, se necessário, para seu caso de uso.

Ativar o fluxo de chave de acesso de toque único no login

Assim como no fluxo de criação da chave de acesso, ele vai seguir a configuração atual para como processar o login do usuário. Em BeginGetPublicKeyCredentialOption, use populatePasskeyData() para coletar as informações relevantes sobre a solicitação de autenticação:

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

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

  // ... other logic as needed
}

Semelhante a CreateEntry, uma instância BiometricPromptData é definida como PublicKeyCredentialEntry. Se não for definido explicitamente, O padrão de allowedAuthenticator é BIOMETRIC_WEAK.

PublicKeyCredentialEntry(
  // other properties...

  biometricPromptData = BiometricPromptData(
    allowedAuthenticators = allowedAuthenticator
  )
)

Processar a seleção de entrada de credenciais

Ao processar a seleção de entrada de credencial para criação de chave de acesso ou seleção de chave de acesso durante o login, chame PendingIntentHandler's retrieveProviderCreateCredentialRequest ou retrieveProviderGetCredentialRequest, conforme apropriado. Eles retornam objetos que contêm os metadados necessários para o provedor. Por exemplo, ao lidar com seleção de entrada para criação da chave de acesso, atualize o código desta forma:

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

Este exemplo contém informações sobre o sucesso do fluxo biométrico. Ele também contém outras informações sobre a credencial. Se o fluxo falhar, use o método em biometricPromptResult.authenticationError para tomar decisões. Os códigos de erro retornados como parte biometricPromptResult.authenticationError.errorCode são os mesmos códigos de erro definido na biblioteca androidx.biometric, como androidx.biometric.BiometricPrompt.NO_SPACE, androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS, androidx.biometric.BiometricPrompt.ERROR_TIMEOUT e semelhantes. O authenticationError também conterá uma mensagem de erro associada ao errorCode que podem ser exibidos em uma interface.

Da mesma forma, extraia metadados durante o retrieveProviderGetCredentialRequest. Verifique se o fluxo biométrico está null. Se sim, configure sua própria biometria para autenticação. Isso é semelhante à forma como a operação get é instrumentada:

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