Credential Manager Holder API की मदद से, Android होल्डर (इसे "वॉलेट" भी कहा जाता है) ऐप्लिकेशन, डिजिटल क्रेडेंशियल मैनेज कर सकता है और उन्हें पुष्टि करने वाले लोगों को दिखा सकता है. इस गाइड में, Credential Manager के साथ अपने होल्डर ऐप्लिकेशन के क्रेडेंशियल रजिस्टर करने का तरीका बताया गया है. साथ ही, यह भी बताया गया है कि जब कोई उपयोगकर्ता कोई क्रेडेंशियल चुनता है, तो प्रज़ेंटेशन के अनुरोध को कैसे मैनेज किया जाता है. Holder API, Android 6 (एपीआई लेवल 23) और इसके बाद के वर्शन पर काम करता है.
डिपेंडेंसी जोड़ें
Credential Manager Holder API का इस्तेमाल करने के लिए, अपने ऐप्लिकेशन मॉड्यूल की build.gradle स्क्रिप्ट में ये डिपेंडेंसी जोड़ें:
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"
}
अपने क्रेडेंशियल रजिस्टर करना
सबसे पहले, RegistryManager का एक इंस्टेंस बनाएं. इसका इस्तेमाल, OpenId4VpRegistry अनुरोध को रजिस्टर करने के लिए किया जाएगा.
// Create the registry manager
val registryManager = RegistryManager.create(context)
OpenId4VpRegistry का अनुरोध बनाएं
पुष्टि करने वालों से OpenID4VP अनुरोधों को मैनेज करने के लिए, आपको OpenId4VpRegistry रजिस्टर करना होगा. मान लें कि आपके पास वॉलेट क्रेडेंशियल (जैसे, sdJwtsFromStorage और mdocsFromStorage) के साथ लोड किए गए स्थानीय डेटा टाइप हैं, तो आपको उन्हें Jetpack DigitalCredentialEntry के बराबर के डेटा टाइप में बदलना होगा:
SdJwtEntry और MdocEntry.
रजिस्ट्री में Sd-JWT जोड़ना
रजिस्ट्री के लिए, हर स्थानीय SD-JWT क्रेडेंशियल को SdJwtEntry से मैप करें:
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
}
रजिस्ट्री में mdocs जोड़ना
अपने स्थानीय mdoc क्रेडेंशियल को 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
}
कोड के बारे में अहम बातें
- एन्क्रिप्ट किए गए आईडी:
IDफ़ील्ड को कॉन्फ़िगर करने का एक तरीका यह है कि एन्क्रिप्ट किए गए क्रेडेंशियल आइडेंटिफ़ायर को रजिस्टर किया जाए. इससे, सिर्फ़ आपके पास वैल्यू को डिक्रिप्ट करने का विकल्प होगा. - स्थानीय भाषा में उपलब्ध कराना: दोनों फ़ॉर्मैट के लिए, यूज़र इंटरफ़ेस (यूआई) के डिसप्ले फ़ील्ड स्थानीय भाषा में उपलब्ध होने चाहिए.
अनुरोधों को मर्ज करना और रजिस्टर करना
बदली गई एंट्री को जोड़ें और अनुरोध को 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.
)
ज़रूरी नहीं: इनलाइन जारी करना
अगर किसी उपयोगकर्ता के पास अनुरोध किए गए टाइप का कोई क्रेडेंशियल मौजूद नहीं है, तो उसे क्रेडेंशियल जोड़ने का विकल्प दिखाया जा सकता है. इसके लिए, अपने OpenId4VpRegistry में, काम करने वाले क्रेडेंशियल वाली inlineIssuanceEntries सूची जोड़ें:
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"
)
CredentialManager में अपने क्रेडेंशियल रजिस्टर करें.
try {
val response = registryManager.registerCredentials(openidRegistryRequest)
} catch (e: Exception) {
// Handle failure
}
ऐप्लिकेशन के मेटाडेटा को मैनेज करना
CredentialManager के साथ रजिस्टर किए गए आपके होल्डर ऐप्लिकेशन के मेटाडेटा में ये प्रॉपर्टी होती हैं:
- सेव रहना: जानकारी को डिवाइस पर सेव किया जाता है. यह डिवाइस को रीबूट करने के बाद भी सेव रहती है.
- साइलो स्टोरेज: हर ऐप्लिकेशन के रजिस्ट्री रिकॉर्ड अलग-अलग सेव किए जाते हैं. इसका मतलब है कि एक ऐप्लिकेशन, दूसरे ऐप्लिकेशन के रजिस्ट्री रिकॉर्ड में बदलाव नहीं कर सकता.
- कुंजी वाले अपडेट: हर ऐप्लिकेशन के रजिस्ट्री रिकॉर्ड को
idसे कुंजीबद्ध किया जाता है. इससे रिकॉर्ड की फिर से पहचान करने, उन्हें अपडेट करने या मिटाने की सुविधा मिलती है. - मेटाडेटा अपडेट करना: जब भी आपके ऐप्लिकेशन में बदलाव हो या उसे पहली बार लोड किया जाए, तब सेव किए गए मेटाडेटा को अपडेट करना एक अच्छा तरीका है. अगर एक ही
idके तहत किसी रजिस्ट्री को कई बार कॉल किया जाता है, तो सबसे हाल ही में किया गया कॉल, पिछले सभी रिकॉर्ड को ओवरराइट कर देता है. इसे अपडेट करने के लिए, पुराने रिकॉर्ड को मिटाए बिना फिर से रजिस्टर करें.
ज़रूरी नहीं: मैचर बनाना
मैचर, एक Wasm बाइनरी है. Credential Manager इसे सैंडबॉक्स में चलाता है, ताकि पुष्टि करने वाले व्यक्ति के अनुरोध के हिसाब से, आपके रजिस्टर किए गए क्रेडेंशियल को फ़िल्टर किया जा सके.
- डिफ़ॉल्ट मैचर:
OpenId4VpRegistryक्लास को इंस्टैंशिएट करने पर, उसमें डिफ़ॉल्टOpenId4VPमैचर (OpenId4VpDefaults.DEFAULT_MATCHER) अपने-आप शामिल हो जाता है. OpenID4VP के सभी स्टैंडर्ड इस्तेमाल के उदाहरणों के लिए, लाइब्रेरी आपके लिए मैचिंग को मैनेज करती है. - कस्टम मैचर: कस्टम मैचर को सिर्फ़ तब लागू किया जा सकता है, जब किसी ऐसे नॉन-स्टैंडर्ड प्रोटोकॉल का इस्तेमाल किया जा रहा हो जिसके लिए मैचिंग लॉजिक की ज़रूरत हो.
चुने गए क्रेडेंशियल को मैनेज करना
जब कोई उपयोगकर्ता किसी क्रेडेंशियल को चुनता है, तो आपके क्रेडेंशियल होल्डर ऐप्लिकेशन को अनुरोध को मैनेज करना होगा.
आपको ऐसी ऐक्टिविटी तय करनी होगी जो androidx.credentials.registry.provider.action.GET_CREDENTIAL इंटेंट फ़िल्टर को सुनती हो.
सैंपल वॉलेट से इस प्रोसेस के बारे में पता चलता है.
इंटेंट, आपकी गतिविधि को पुष्टि करने वाले के अनुरोध और कॉल करने वाले के ऑरिजिन के साथ लॉन्च करता है. इसे PendingIntentHandler.retrieveProviderGetCredentialRequest फ़ंक्शन की मदद से निकाला जाता है. इससे ProviderGetCredentialRequest मिलता है. इसमें, पुष्टि करने वाले के अनुरोध से जुड़ी सारी जानकारी होती है. इसके तीन मुख्य कॉम्पोनेंट हैं:
- कॉल करने वाला ऐप्लिकेशन: अनुरोध करने वाला ऐप्लिकेशन, जिसे
getCallingAppInfoकी मदद से वापस लाया जा सकता है. इसकी मदद से, पुष्टि करने वाले की पहचान की जांच की जा सकती है. - चुना गया क्रेडेंशियल: इस बारे में जानकारी कि उपयोगकर्ता ने कौनसा क्रेडेंशियल चुना है. यह जानकारी
selectedCredentialSet extension methodसे हासिल की जाती है. यह जानकारी, आपके रजिस्टर किए गए क्रेडेंशियल आईडी से मैच करेगी. - खास अनुरोध: पुष्टि करने वाले व्यक्ति या इकाई का खास अनुरोध, जिसे
getCredentialOptionsतरीके से वापस पाया गया है. डिजिटल क्रेडेंशियल के अनुरोध के फ़्लो के लिए, आपको इस सूची में एकGetDigitalCredentialOptionदिख सकता है.
प्रज़ेंटेशन के अनुरोध को इस कोड की मदद से प्रोसेस किया जा सकता है:
request.credentialOptions.forEach { option ->
if (option is GetDigitalCredentialOption) {
Log.i(TAG, "Got DC request: ${option.requestJson}")
processRequest(option.requestJson)
}
}
इसका एक उदाहरण सैंपल वॉलेट में देखा जा सकता है.
पुष्टि करने वाले की पहचान की जांच करना
सबसे पहले, इंटेंट से ProviderGetCredentialRequest को निकालें:
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
खास अधिकार वाले ऐप्लिकेशन देखें: खास अधिकार वाले ऐप्लिकेशन (जैसे, वेब ब्राउज़र), ऑरिजिन पैरामीटर सेट करके, पुष्टि करने वाले अन्य ऐप्लिकेशन की ओर से कॉल कर सकते हैं. इस ऑरिजिन को वापस पाने के लिए, CallingAppInfo getOrigin एपीआई को खास अधिकार वाले और भरोसेमंद कॉलर की सूची (JSON फ़ॉर्मैट में अनुमति वाली सूची) पास करें.
val origin = request?.callingAppInfo?.getOrigin(
privilegedAppsJson // Your allow list JSON
)
अगर origin खाली नहीं है: अगर packageName और सर्टिफ़िकेट फ़िंगरप्रिंट, अनुमति वाली सूची में मौजूद किसी ऐप्लिकेशन से मैच करते हैं, तो ऑरिजिन की जानकारी दिखती है. इसे खास अधिकार वाला कॉल मानें और कॉलिंग ऐप्लिकेशन के सिग्नेचर का इस्तेमाल करके ऑरिजिन का हिसाब लगाने के बजाय, OpenID4VP रिस्पॉन्स पर इस ऑरिजिन को सेट करें.
अगर origin खाली है, तो इसका मतलब है कि पुष्टि करने वाले का अनुरोध, किसी Android ऐप्लिकेशन से आया है. OpenID4VP रिस्पॉन्स से मैप किए गए ऑरिजिन को 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"
होल्डर यूज़र इंटरफ़ेस (यूआई) रेंडर करना
क्रेडेंशियल चुनने पर, होल्डर ऐप्लिकेशन को शुरू किया जाता है. इससे उपयोगकर्ता को ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) के बारे में जानकारी मिलती है. इस वर्कफ़्लो को मैनेज करने के दो स्टैंडर्ड तरीके हैं:
- अगर क्रेडेंशियल रिलीज़ करने के लिए, उपयोगकर्ता की पहचान की पुष्टि करने की ज़रूरत है, तो BiometricPrompt API का इस्तेमाल करें. इसे सैंपल में दिखाया गया है.
- इसके अलावा, कई वॉलेट, खाली गतिविधि रेंडर करके, बिना किसी सूचना के डेटा वापस भेज देते हैं. इससे डेटा, कॉलिंग ऐप्लिकेशन को तुरंत वापस मिल जाता है. इससे उपयोगकर्ता को कम क्लिक करने पड़ते हैं और उसे बेहतर अनुभव मिलता है.
क्रेडेंशियल का रिस्पॉन्स वापस करना
जब आपका होल्डर ऐप्लिकेशन, नतीजे को वापस भेजने के लिए तैयार हो जाए, तो क्रेडेंशियल के जवाब के साथ गतिविधि को पूरा करें:
PendingIntentHandler.setGetCredentialResponse(
resultData,
GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()
अगर कोई अपवाद है, तो क्रेडेंशियल अपवाद को इस तरह भेजा जा सकता है:
PendingIntentHandler.setGetCredentialException(
resultData,
GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()
कॉन्टेक्स्ट में क्रेडेंशियल रिस्पॉन्स दिखाने का पूरा उदाहरण देखने के लिए, सैंपल के तौर पर मिला ऐप्लिकेशन देखें.