Credential Manager Holder API memungkinkan aplikasi pemegang (juga disebut "dompet") Android Anda mengelola dan menampilkan kredensial digital kepada pemverifikasi. Panduan ini menjelaskan cara mendaftarkan kredensial aplikasi pemegang Anda ke Credential Manager dan cara menangani permintaan presentasi saat pengguna memilih kredensial. Holder API didukung di Android 6 (API level 23) dan yang lebih tinggi.
Menambahkan dependensi
Untuk menggunakan Credential Manager Holder API, tambahkan dependensi berikut ke skrip build.gradle modul aplikasi Anda:
dependencies {
// Used to implement credential registries
implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha05"
implementation "androidx.credentials.registry:registry-digitalcredentials-openid:1.0.0-alpha05"
implementation "androidx.credentials.registry:registry-digitalcredentials-sdjwtvc:1.0.0-alpha05"
implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha05"
implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha05"
}
Mendaftarkan kredensial Anda
Pertama, buat instance RegistryManager yang akan Anda gunakan untuk mendaftarkan permintaan OpenId4VpRegistry.
// Create the registry manager
val registryManager = RegistryManager.create(context)
Membuat permintaan OpenId4VpRegistry
Anda harus mendaftarkan OpenId4VpRegistry untuk menangani permintaan OpenID4VP dari
pemverifikasi. Dengan asumsi Anda memiliki jenis data lokal yang dimuat dengan kredensial
wallet (misalnya, sdJwtsFromStorage dan mdocsFromStorage), Anda harus
mengonversinya menjadi setara Jetpack DigitalCredentialEntry:
SdJwtEntry dan MdocEntry.
Menambahkan SD-JWT ke registry
Petakan setiap kredensial SD-JWT lokal ke SdJwtEntry untuk registry:
fun mapToSdJwtEntries(sdJwtsFromStorage: List<StoredSdJwtEntry>): List<SdJwtEntry> {
val list = mutableListOf<SdJwtEntry>()
for (sdJwt in sdJwtsFromStorage) {
list.add(
SdJwtEntry(
verifiableCredentialType = sdJwt.getVCT(),
claims = sdJwt.getClaimsList(),
entryDisplayPropertySet = sdJwt.toDisplayProperties(),
id = sdJwt.getId() // Make sure this cannot be readily guessed
)
)
}
return list
}
Menambahkan mdoc ke Registry
Petakan kredensial mdoc lokal Anda ke jenis Jetpack MdocEntry:
fun mapToMdocEntries(mdocsFromStorage: List<StoredMdocEntry>): List<MdocEntry> {
val list = mutableListOf<MdocEntry>()
for (mdoc in mdocsFromStorage) {
list.add(
MdocEntry(
docType = mdoc.retrieveDocType(),
fields = mdoc.getFields(),
entryDisplayPropertySet = mdoc.toDisplayProperties(),
id = mdoc.getId() // Make sure this cannot be readily guessed
)
)
}
return list
}
Poin penting tentang kode
- ID Terenkripsi: Salah satu metode untuk mengonfigurasi kolom
IDadalah dengan mendaftarkan ID kredensial terenkripsi, sehingga hanya Anda yang dapat mendekripsi nilainya. - Pelokalan: Kolom tampilan UI untuk kedua format harus dilokalkan.
Menggabungkan dan mendaftarkan permintaan Anda
Gabungkan entri yang dikonversi dan daftarkan permintaan dengan
RegistryManager:
val credentialEntries =
mapToSdJwtEntries(sdJwtsFromStorage) + mapToMdocEntries(mdocsFromStorage)
val openidRegistryRequest = OpenId4VpRegistry(
credentialEntries = credentialEntries,
id = "my-wallet-openid-registry-v1" // A stable, unique ID to identify your registry record.
)
Opsional: Penerbitan inline
Jika tidak ada kredensial yang ada dari jenis yang diminta yang tersedia untuk pengguna,
Anda dapat menampilkan opsi untuk menambahkan kredensial ke pemegang Anda. Untuk melakukannya, tambahkan
daftar inlineIssuanceEntries yang berisi kredensial yang didukung ke
OpenId4VpRegistry Anda:
val openidRegistryRequest = OpenId4VpRegistry(
credentialEntries = credentialEntries,
inlineIssuanceEntries = emptyList(),
listOf(
MdocInlineIssuanceEntry(
id = "Issuance",
display = InlineIssuanceEntry.InlineIssuanceDisplayProperties(
subtitle = "Mobile Drivers License, State Id, and Others",
),
supportedMdocs = setOf(
MdocInlineIssuanceEntry.SupportedMdoc(
"eu.europa.ec.eudi.pid.1"
),
MdocInlineIssuanceEntry.SupportedMdoc(
"org.iso.18013.5.1.mDL1"
),
)
),
SdJwtInlineIssuanceEntry(
id = "sd-jwt-issuance",
display = InlineIssuanceEntry.InlineIssuanceDisplayProperties(
subtitle = "Mobile Drivers License, State Id, and Others",
),
supportedSdJwts = setOf(
SdJwtInlineIssuanceEntry.SupportedSdJwt("urn:openid:interop:id:1")
)
)
),
id = "my-wallet-openid-registry-v1"
)
Daftarkan kredensial Anda dengan CredentialManager.
try {
val response = registryManager.registerCredentials(openidRegistryRequest)
} catch (e: Exception) {
// Handle failure
}
Pengelolaan metadata aplikasi
Metadata yang didaftarkan aplikasi pemegang Anda ke CredentialManager memiliki properti berikut:
- Persistensi: Informasi disimpan secara lokal, dan tetap ada setelah perangkat dimulai ulang.
- Penyimpanan Terpisah: Setiap data registry aplikasi disimpan secara terpisah, yang berarti satu aplikasi tidak dapat mengubah data registry aplikasi lain.
- Update dengan Kunci: Setiap data registry aplikasi diberi kunci dengan
id, yang memungkinkan identifikasi ulang, update, atau penghapusan data. - Memperbarui Metadata: Sebaiknya perbarui metadata yang dipertahankan setiap kali aplikasi Anda berubah atau pertama kali dimuat. Jika registry dipanggil beberapa kali dalam
idyang sama, panggilan terbaru akan menimpa semua data sebelumnya. Untuk memperbarui, daftar ulang tanpa perlu menghapus data lama terlebih dahulu.
Opsional: Membuat matcher
Matcher adalah biner Wasm yang dijalankan Credential Manager di sandbox untuk memfilter kredensial terdaftar Anda terhadap permintaan Verifier yang masuk.
- Pencocok default: Class
OpenId4VpRegistryotomatis menyertakan pencocokOpenId4VPdefault (OpenId4VpDefaults.DEFAULT_MATCHER) saat Anda membuat instance-nya. Untuk semua kasus penggunaan OpenID4VP standar, library akan menangani pencocokan untuk Anda. - Pencocok kustom: Anda hanya akan menerapkan pencocok kustom jika Anda mendukung protokol non-standar yang memerlukan logika pencocokannya sendiri.
Menangani kredensial yang dipilih
Saat pengguna memilih kredensial, aplikasi pemegang Anda harus menangani permintaan tersebut.
Anda harus menentukan Aktivitas yang memproses
filter intent androidx.credentials.registry.provider.action.GET_CREDENTIAL.
Wallet contoh kami menunjukkan prosedur ini.
Intent meluncurkan aktivitas Anda dengan permintaan Verifier dan origin panggilan,
yang Anda ekstrak dengan
PendingIntentHandler.retrieveProviderGetCredentialRequest
fungsi. Tindakan ini akan menampilkan ProviderGetCredentialRequest
yang berisi semua informasi yang terkait dengan permintaan pemverifikasi. Ada
tiga komponen utama:
- Aplikasi pemanggil: Aplikasi yang membuat permintaan, dapat diambil dengan
getCallingAppInfo. Anda dapat menggunakannya untuk memeriksa identitas pemverifikasi. - Kredensial yang dipilih: Informasi tentang kandidat yang telah dipilih pengguna, yang diambil melalui
selectedCredentialSet extension method; kredensial ini akan cocok dengan ID kredensial yang Anda daftarkan. - Permintaan spesifik: Permintaan spesifik yang dibuat oleh pemverifikasi, yang diambil
dari metode
getCredentialOptions. Untuk alur permintaan Digital Credentials, Anda dapat menemukan satuGetDigitalCredentialOptiondalam daftar ini.
Anda dapat memproses permintaan presentasi dengan kode berikut:
request.credentialOptions.forEach { option ->
if (option is GetDigitalCredentialOption) {
Log.i(TAG, "Got DC request: ${option.requestJson}")
processRequest(option.requestJson)
}
}
Contohnya dapat dilihat di contoh wallet.
Memeriksa identitas pemverifikasi
Pertama, ekstrak ProviderGetCredentialRequest dari intent:
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
Periksa aplikasi dengan hak istimewa: Aplikasi dengan hak istimewa (seperti browser web) dapat melakukan panggilan atas nama pemverifikasi lain dengan menetapkan parameter origin. Untuk mengambil
origin ini, teruskan daftar pemanggil dengan hak istimewa dan tepercaya (daftar yang diizinkan dalam format
JSON) ke CallingAppInfo getOrigin API.
val origin = request?.callingAppInfo?.getOrigin(
privilegedAppsJson // Your allow list JSON
)
Jika origin tidak kosong: Origin akan ditampilkan jika packageName dan
sidik jari sertifikat cocok dengan aplikasi dalam daftar yang diizinkan. Anggap ini sebagai
panggilan dengan hak istimewa dan tetapkan origin ini pada respons OpenID4VP, bukan
menghitung origin menggunakan tanda tangan aplikasi panggilan.
Jika origin kosong: Permintaan verifikator berasal dari aplikasi Android. Origin
yang dipetakan ke respons OpenID4VP harus dihitung sebagai
android:apk-key-hash:<encoded SHA 256 fingerprint>.
val appSigningInfo =
request?.callingAppInfo?.signingInfoCompat?.signingCertificateHistory?.get(0)?.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val certHash =
Base64.encodeToString(md.digest(appSigningInfo), Base64.NO_WRAP or Base64.NO_PADDING)
val computedOrigin = "android:apk-key-hash:$certHash"
Merender UI Pemegang
Saat kredensial dipilih, aplikasi pemegang akan dipanggil, yang memandu pengguna melalui UI aplikasi. Ada dua cara standar untuk menangani alur kerja ini:
- Jika autentikasi pengguna tambahan diperlukan untuk merilis kredensial, gunakan BiometricPrompt API. Hal ini ditunjukkan dalam contoh.
- Jika tidak, banyak dompet memilih pengembalian otomatis dengan merender aktivitas kosong yang langsung meneruskan data kembali ke aplikasi panggilan. Hal ini meminimalkan klik pengguna dan memberikan pengalaman yang lebih lancar.
Menampilkan respons kredensial
Setelah aplikasi pemegang Anda siap mengirimkan kembali hasilnya, selesaikan aktivitas dengan respons kredensial:
PendingIntentHandler.setGetCredentialResponse(
resultData,
GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()
Jika ada pengecualian, Anda juga dapat mengirim pengecualian kredensial:
PendingIntentHandler.setGetCredentialException(
resultData,
GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()
Lihat aplikasi contoh untuk mengetahui contoh lengkap menampilkan respons kredensial dalam konteks.