En esta guía, se continúa con la implementación del uso de llaves de acceso para la autenticación. Antes de que tus usuarios puedan acceder con llaves de acceso, también debes completar las instrucciones en Cómo crear llaves de acceso.
Para autenticarte con una llave de acceso, primero debes recuperar las opciones necesarias para recuperar la clave pública de tu servidor de aplicaciones y, luego, llamar a la API de Credential Manager para recuperar la clave pública. Luego, controla la respuesta de inicio de sesión de forma adecuada.
Descripción general
En esta guía, se explican los cambios necesarios en tu app cliente para acceder con una llave de acceso y se proporciona una breve descripción general de la implementación del servidor de la app. Para obtener más información sobre la integración del servidor, consulta Autenticación con llave de acceso del servidor.
Para recuperar todas las opciones de llaves de acceso y contraseñas asociadas con la cuenta del usuario, completa estos pasos:
- Obtén opciones de solicitud de credenciales del servidor: Realiza una solicitud desde tu app a tu servidor de autenticación para iniciar el proceso de acceso con llave de acceso. Desde el servidor, envía las opciones necesarias para obtener la credencial de clave pública, así como un desafío único.
- Crea el objeto necesario para obtener la credencial de clave pública: Envuelve las opciones que envía el servidor en un objeto
GetPublicKeyCredentialOption. - (Opcional) Prepara getCredential: En Android 14 y versiones posteriores, puedes reducir la latencia mostrando el selector de cuentas con el método
prepareGetCredential()antes de llamar agetCredential(). - Inicia el flujo de acceso: Llama al método
getCredential()para permitir que el usuario acceda. - Administra la respuesta: Administra cada una de las posibles respuestas de credenciales.
- Controla las excepciones: Asegúrate de controlar las excepciones de forma adecuada.
1. Obtén opciones de solicitud de credenciales del servidor
Solicita al servidor las opciones necesarias para obtener las credenciales de clave pública, así como el challenge, que es único para cada intento de acceso. Para obtener más información sobre la implementación del servidor, consulta Crea el desafío y Crea opciones de solicitud de credenciales.
Las opciones se verán similares a las siguientes:
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
Para obtener más información sobre los campos, consulta la entrada de blog sobre el acceso con una llave de acceso.
2. Crea el objeto necesario para obtener la credencial de clave pública
En tu app, usa las opciones para crear un objeto GetPublicKeyCredentialOption.
En el siguiente ejemplo, requestJson representa las opciones que envía el 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
)
Luego, une GetPublicKeyCredentialOption en un 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: Reduce la latencia de acceso
En Android 14 o versiones posteriores, puedes reducir la latencia cuando se muestra el selector de cuentas con el método prepareGetCredential() antes de llamar a getCredential().
El método prepareGetCredential() devuelve un objeto PrepareGetCredentialResponse que se almacena en caché. Esto permite que el método getCredential() del siguiente paso muestre el selector de cuenta con los datos almacenados en caché.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
4. Inicia el flujo de acceso.
Llama al método getCredential() para mostrarle al usuario el selector de cuentas. Usa el siguiente fragmento de código como referencia para iniciar el flujo de acceso:
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. Cómo controlar la respuesta
Controla la respuesta, que puede contener uno de varios tipos de objetos de credenciales.
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")
}
}
}
El PublicKeyCredential que se devuelve de la autenticación es, básicamente, una aserción firmada, estructurada de la siguiente manera:
{
"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>"
}
}
En el servidor, debes verificar la credencial. Para obtener más información, consulta Cómo verificar y acceder al usuario.
6. Cómo controlar excepciones
Debes controlar todas las excepciones de subclase de GetCredentialException.
Para obtener información sobre cómo controlar cada excepción, consulta la guía de solución de problemas.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}
Próximos pasos
- Cómo administrar llaves de acceso
- Comprende los flujos de experiencia del usuario con llaves de acceso