Este guia continua a implementação do uso de chaves de acesso para autenticação. Antes que os usuários possam fazer login com chaves de acesso, você também precisa concluir as instruções em Criar chaves de acesso.
Para fazer a autenticação com uma chave de acesso, primeiro recupere as opções necessárias para recuperar a chave pública do seu servidor de apps e chame a API Credential Manager para recuperar a chave pública. Em seguida, processe a resposta de login de maneira adequada.
Visão geral
Este guia se concentra nas mudanças necessárias no app cliente para fazer login do usuário com uma chave de acesso e oferece uma breve visão geral da implementação do lado do servidor do app. Para saber mais sobre a integração do lado do servidor, consulte Autenticação de chave de acesso do lado do servidor.
Para extrair todas as opções de chave de acesso e senha associadas à conta do usuário, siga estas etapas:
- Receber opções de solicitação de credenciais do servidor: faça uma solicitação do app para o servidor de autenticação e inicie o processo de login com chave de acesso. Do servidor, envie as opções necessárias para receber a credencial de chave pública, além de um desafio exclusivo.
- Crie o objeto necessário para receber a credencial de chave pública: encapsule
as opções enviadas pelo servidor em um objeto
GetPublicKeyCredentialOption. - (opcional) Prepare o getCredential: no Android 14 e em versões mais recentes, é possível
reduzir a latência mostrando o seletor de contas usando o
método
prepareGetCredential()antes de chamargetCredential(). - Inicie o fluxo de login: chame o método
getCredential()para fazer login do usuário. - Processar a resposta: processe cada uma das possíveis respostas de credencial.
- Processar exceções: processe as exceções de maneira adequada.
1. Receber opções de solicitação de credenciais do servidor
Solicite ao servidor as opções necessárias para receber as credenciais de chave pública,
bem como o challenge, que é exclusivo para cada tentativa de login. Para saber mais sobre a implementação do lado do servidor, consulte Criar o desafio e Criar opções de solicitação de credenciais.
As opções são semelhantes a estas:
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
Para saber mais sobre os campos, consulte a postagem do blog sobre como fazer login com uma chave de acesso.
2. Criar o objeto necessário para receber a credencial de chave pública
No app, use as opções para criar um objeto GetPublicKeyCredentialOption.
No exemplo a seguir, requestJson representa as opções enviadas pelo servidor.
// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()
// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
requestJson = requestJson
)
Em seguida, encapsule GetPublicKeyCredentialOption em um objeto GetCredentialRequest.
val credentialRequest = GetCredentialRequest(
// Include all the sign-in options that your app supports.
listOf(getPasswordOption, getPublicKeyCredentialOption),
// Defines whether you prefer to use only immediately available
// credentials or hybrid credentials.
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)
3. Opcional: reduzir a latência de login
No Android 14 ou em versões mais recentes, é possível reduzir a latência ao mostrar o seletor
de contas usando o método prepareGetCredential() antes de chamar
getCredential().
O método prepareGetCredential() retorna um objeto
PrepareGetCredentialResponse que é armazenado em cache. Isso permite que o método
getCredential() na etapa a seguir mostre o seletor de contas
com os dados armazenados em cache.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
4. Inicie o fluxo de login
Chame o método getCredential() para mostrar o seletor de contas ao usuário. Use o
snippet de código a seguir como referência para iniciar o fluxo de login:
coroutineScope {
try {
result = credentialManager.getCredential(
// Use an activity-based context to avoid undefined system UI
// launching behavior.
context = activityContext,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
5. Processar a resposta
Processe a resposta, que pode conter um de vários tipos de objetos de credencial.
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")
}
}
}
O PublicKeyCredential retornado da autenticação é essencialmente uma declaração
assinada, estruturada da seguinte maneira:
{
"id": "<credential ID>",
"type": "public-key",
"rawId": "<raw credential ID>",
"response": {
"clientDataJSON": "<signed client data containing challenge>",
"authenticatorData": "<authenticator metadata>",
"signature": "<digital signature to be verified>",
"userHandle": "<user ID from credential registration>"
}
}
No servidor, você precisa verificar a credencial. Para saber mais, consulte Verificar e fazer login do usuário.
6. Processar exceções
Você precisa processar todas as exceções de subclasse de GetCredentialException.
Para saber como lidar com cada exceção, consulte o guia de solução de problemas.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}