Panduan ini melanjutkan implementasi penggunaan kunci sandi untuk autentikasi. Sebelum pengguna dapat login dengan kunci sandi, Anda juga harus menyelesaikan petunjuk di Membuat kunci sandi.
Untuk melakukan autentikasi dengan kunci sandi, Anda harus mengambil opsi yang diperlukan untuk mengambil kunci publik dari server aplikasi terlebih dahulu, lalu memanggil Credential Manager API untuk mengambil kunci publik. Kemudian, tangani respons login dengan tepat.
Ringkasan
Panduan ini berfokus pada perubahan yang diperlukan di aplikasi klien Anda untuk membuat pengguna login dengan kunci sandi, dan memberikan ringkasan singkat tentang implementasi sisi server aplikasi. Untuk mempelajari integrasi sisi server lebih lanjut, lihat Autentikasi kunci sandi sisi server.
Untuk mengambil semua opsi kunci sandi dan sandi yang dikaitkan dengan akun pengguna, selesaikan langkah-langkah berikut:
- Mendapatkan opsi permintaan kredensial dari server: Buat permintaan dari aplikasi Anda ke server autentikasi untuk memulai proses login kunci sandi. Dari server, kirim opsi yang diperlukan untuk mendapatkan kredensial kunci publik, serta tantangan unik.
- Membuat objek yang diperlukan untuk mendapatkan kredensial kunci publik: Gabungkan
opsi yang dikirim oleh server dalam objek
GetPublicKeyCredentialOption - (opsional) Menyiapkan getCredential: Di Android 14 dan yang lebih tinggi, Anda dapat
mengurangi latensi dengan menampilkan pemilih akun menggunakan
prepareGetCredential()metode sebelum memanggilgetCredential(). - Meluncurkan alur login: Panggil metode
getCredential()untuk membuat pengguna login - Menangani respons: Tangani setiap kemungkinan respons kredensial.
- Menangani pengecualian: Pastikan Anda menangani pengecualian dengan tepat.
Mendapatkan opsi permintaan kredensial dari server
Minta server untuk opsi yang diperlukan guna mendapatkan kredensial kunci publik, serta challenge, yang unik untuk setiap upaya login. Untuk mempelajari
implementasi sisi server lebih lanjut, lihat Membuat
tantangan dan Membuat opsi permintaan kredensial.
Opsi ini terlihat mirip dengan berikut:
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
Untuk mempelajari kolom lebih lanjut, lihat postingan blog tentang login dengan kunci sandi.
Membuat objek yang diperlukan untuk mendapatkan kredensial kunci publik
Di aplikasi Anda, gunakan opsi untuk membuat objek GetPublicKeyCredentialOption.
Dalam contoh berikut, requestJson mewakili opsi yang dikirim oleh server.
// 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
)
Kemudian, gabungkan GetPublicKeyCredentialOption dalam objek 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
)
Opsional: Mengurangi latensi login
Di Android 14 atau yang lebih baru, Anda dapat mengurangi latensi saat menampilkan pemilih akun
dengan menggunakan metode prepareGetCredential() sebelum memanggil
getCredential().
Metode prepareGetCredential() menampilkan objek
PrepareGetCredentialResponse yang di-cache. Hal ini memungkinkan metode getCredential() pada langkah berikutnya menampilkan pemilih akun dengan data yang di-cache.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
Meluncurkan alur login
Panggil metode getCredential() untuk menampilkan pemilih akun kepada pengguna. Gunakan cuplikan kode berikut sebagai referensi cara meluncurkan alur login:
// Use an activity-based context to avoid undefined system UI
// launching behavior.
val context = MutableContextWrapper(activityContext)
coroutineScope {
try {
result = credentialManager.getCredential(
// Use MutableContextWrapper to avoid memory leak during configuration changes
context = context,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
Menangani respons
Tangani respons, yang dapat berisi salah satu dari berbagai jenis objek kredensial.
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")
}
}
}
PublicKeyCredential yang ditampilkan dari autentikasi pada dasarnya adalah pernyataan yang ditandatangani, yang disusun sebagai berikut:
{
"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>"
}
}
Di server, Anda harus memverifikasi kredensial. Untuk mempelajari lebih lanjut, lihat Memverifikasi dan membuat pengguna login.
Menangani pengecualian
Anda harus menangani semua pengecualian sub-class dari GetCredentialException.
Untuk mempelajari cara menangani setiap pengecualian, lihat panduan pemecahan masalah.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}