Kart Sahibi uygulamanızı Kimlik Bilgisi Yöneticisi ile entegre etme

Credential Manager Holder API, Android sahibi (aynı zamanda "cüzdan" olarak da adlandırılır) uygulamanızın doğrulayıcılara dijital kimlik bilgilerini yönetmesini ve sunmasını sağlar.

Kimlik Yöneticisi'ndeki dijital kimlik kullanıcı arayüzünü gösteren resim
Şekil 1. Dijital kimlik bilgisi seçici kullanıcı arayüzü.

Temel kavramlar

Holder API'yi kullanmadan önce aşağıdaki kavramlar hakkında bilgi edinmeniz önemlidir.

Kimlik bilgisi biçimleri

Kimlik bilgileri, farklı kimlik bilgisi biçimlerinde sahibi uygulamalarında saklanabilir. Bu biçimler, kimlik bilgilerinin nasıl gösterilmesi gerektiğiyle ilgili spesifikasyonlardır ve her biri kimlik bilgisiyle ilgili aşağıdaki bilgileri içerir:

  • Tür: Üniversite diploması veya mobil sürücü belgesi gibi bir kategori.
  • Özellikler: Ad ve soyadı gibi özellikler.
  • Kodlama: Kimlik bilgisinin yapılandırılma şekli (ör. SD-JWT veya mdoc)
  • Geçerlilik: Kimlik bilgisinin gerçekliğini kriptografik olarak doğrulama yöntemi.

Her kimlik bilgisi biçimi kodlamayı ve doğrulamayı biraz farklı şekilde yapar ancak işlevsel olarak aynıdırlar.

Kayıt defteri iki biçimi destekler:

Doğrulayıcı, Credential Manager'ı kullanırken SD-JWT ve mdoc için OpenID4VP isteğinde bulunabilir. Seçim, kullanım alanına ve sektöre göre değişir.

Kimlik bilgisi meta verileri kaydı

Kimlik Bilgisi Yöneticisi, sahibinin kimlik bilgilerini doğrudan değil, kimlik bilgilerinin meta verilerini depolar. Bir kart sahibi uygulaması, önce RegistryManager kullanarak kimlik bilgisi meta verilerini Kimlik Bilgisi Yöneticisi'ne kaydetmelidir. Bu kayıt işlemi, iki temel amaca hizmet eden bir kayıt kaydı oluşturur:

  • Eşleştirme: Kayıtlı kimlik bilgisi meta verileri, gelecekteki doğrulayıcı istekleriyle eşleştirmek için kullanılır.
  • Görüntüleme: Özelleştirilmiş kullanıcı arayüzü öğeleri, kimlik seçici arayüzünde kullanıcıya gösterilir.

Hem mdoc hem de SD-JWT yeterlilik belgesi biçimlerini desteklediği için dijital yeterlilik belgelerinizi kaydetmek üzere OpenId4VpRegistry sınıfını kullanacaksınız. Doğrulayıcılar, bu kimlik bilgilerini istemek için OpenID4VP istekleri gönderir.

Uygulamanızın kimlik bilgilerini kaydetme

Credential Manager Holder API'yi kullanmak için aşağıdaki bağımlılıkları uygulama modülünüzün derleme komut dosyasına ekleyin:

Groovy

dependencies {
    // Use to implement credentials registrys

    implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha04"
    implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04"

}

Kotlin

dependencies {
    // Use to implement credentials registrys

    implementation("androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider:1.0.0-alpha04")
    implementation("androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04")

}

RegistryManager'ı oluşturma

RegistryManager örneği oluşturun ve OpenId4VpRegistry isteğini bu örnekle kaydedin.

// Create the registry manager
val registryManager = RegistryManager.create(context)

// The guide covers how to build this out later
val registryRequest = OpenId4VpRegistry(credentialEntries, id)

try {
    registryManager.registerCredentials(registryRequest)
} catch (e: Exception) {
    // Handle exceptions
}

OpenId4VpRegistry isteği oluşturma

Daha önce de belirtildiği gibi, doğrulayıcıdan gelen OpenID4VP isteğini işlemek için bir OpenId4VpRegistry kaydetmeniz gerekir. Cüzdan kimlik bilgilerinizle yüklenmiş bazı yerel veri türleriniz olduğunu varsayacağız (örneğin, sdJwtsFromStorage). Artık bunları, biçimlerine göre Jetpack DigitalCredentialEntry eşdeğerlerine dönüştüreceksiniz. SD-JWT veya mdoc için sırasıyla SdJwtEntry veya MdocEntry.

Kayıt defterine Sd-JWT'ler ekleme

Her bir yerel SD-JWT kimlik bilgisini kayıt için bir SdJwtEntry ile eşleyin:

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
}

Kayıt defterine mdoc ekleme

Yerel mdoc kimlik bilgilerinizi Jetpack türü MdocEntry ile eşleyin:

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
}

Kodla ilgili önemli noktalar

  • id alanını yapılandırmanın bir yöntemi, şifrelenmiş bir kimlik bilgisi tanımlayıcısı kaydetmektir. Böylece, değeri yalnızca siz şifreleyebilirsiniz.
  • Her iki biçimin kullanıcı arayüzü görüntüleme alanları yerelleştirilmelidir.

Kimlik bilgilerinizi kaydetme

Dönüştürülen girişlerinizi birleştirin ve isteği RegistryManager ile kaydedin:

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.
)

Şimdi kimlik bilgilerinizi CredentialManager'a kaydetmeye hazırız.

try {
    val response = registryManager.registerCredentials(openidRegistryRequest)
} catch (e: Exception) {
    // Handle failure
}

Kimlik bilgilerinizi artık Kimlik Bilgisi Yöneticisi'ne kaydettiniz.

Uygulama meta verileri yönetimi

Cüzdan uygulamanızın CredentialManager'a kaydettiği meta veriler aşağıdaki özelliklere sahiptir:

  • Kalıcılık: Bilgiler yerel olarak kaydedilir ve yeniden başlatma işlemlerinde kalıcı olur.
  • Yalıtılmış Depolama: Her uygulamanın kayıt defteri kayıtları ayrı olarak depolanır. Bu nedenle bir uygulama, başka bir uygulamanın kayıt defteri kayıtlarını değiştiremez.
  • Anahtarlı Güncellemeler: Her uygulamanın kayıt defteri kayıtları bir id ile anahtarlanır. Bu, kayıtların yeniden tanımlanmasına, güncellenmesine veya silinmesine olanak tanır.
  • Meta verileri güncelleme: Uygulamanız her değiştiğinde veya ilk kez yüklendiğinde kalıcı meta verileri güncellemek iyi bir uygulamadır. Bir kayıt defteri aynı id altında birden fazla kez çağrılırsa en son çağrı, önceki tüm kayıtların üzerine yazar. Güncellemek için eski kaydı önce temizlemenize gerek kalmadan yeniden kaydolun.

İsteğe bağlı: Eşleştirici oluşturma

Eşleştirici, Credential Manager'ın gelen bir doğrulayıcı isteğine karşı kayıtlı kimlik bilgilerinizi filtrelemek için sanal ortamda çalıştırdığı bir Wasm ikilisidir.

  • Varsayılan eşleştirici: OpenId4VpRegistry sınıfı, oluşturduğunuzda varsayılan OpenId4VP eşleştiriciyi otomatik olarak içerir (OpenId4VpDefaults.DEFAULT_MATCHER). Kitaplık, tüm standart OpenID4VP kullanım alanlarında eşleşme işlemini sizin için gerçekleştirir.
  • Özel eşleştirici: Özel eşleştiriciyi yalnızca kendi eşleşme mantığını gerektiren standart dışı bir protokolü destekliyorsanız uygularsınız.

Seçili bir kimlik bilgisini kullanma

Kullanıcı bir kimlik bilgisi seçtiğinde, kart sahibi uygulamanız isteği işlemelidir. androidx.credentials.registry.provider.action.GET_CREDENTIAL amaç filtresini dinleyen bir etkinlik tanımlamanız gerekir. Örnek cüzdanımızda bu prosedür gösterilmektedir.

Amaç, etkinliğinizi doğrulayıcı isteği ve arama kaynağıyla başlatır. Bunları PendingIntentHandler.retrieveProviderGetCredentialRequest işleviyle ayıklarsınız. Bu işlev, doğrulayıcı isteğiyle ilişkili tüm bilgileri içeren bir ProviderGetCredentialRequest döndürür. Üç temel bileşen vardır:

  • Arama uygulaması: İsteği yapan uygulama. getCallingAppInfo ile alınabilir.
  • Seçilen yeterlilik belgesi: Kullanıcının hangi adayı seçtiğiyle ilgili bilgiler, selectedCredentialSet extension method aracılığıyla alınır. Bu, kaydettiğiniz yeterlilik belgesi kimliğiyle eşleşir.
  • Belirli istekler: Doğrulayan tarafından yapılan ve getCredentialOptions yönteminden alınan belirli istek. Dijital kimlik bilgisi isteği akışında bu listede tek bir GetDigitalCredentialOption bulabilirsiniz.

Doğrulayıcı en sık olarak dijital kimlik bilgisi sunma isteğinde bulunur. Bu isteği aşağıdaki örnek kodla işleyebilirsiniz:

request.credentialOptions.forEach { option ->
    if (option is GetDigitalCredentialOption) {
        Log.i(TAG, "Got DC request: ${option.requestJson}")
        processRequest(option.requestJson)
    }
}

Bunun bir örneğini örnek cüzdanda görebilirsiniz.

Doğrulayıcı kimliğini kontrol etme

  1. Amacın ProviderGetCredentialRequest bölümünü ayıklayın:
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
  1. Ayrıcalıklı Kaynak olup olmadığını kontrol edin: Ayrıcalıklı uygulamalar (web tarayıcıları gibi), kaynak parametresini ayarlayarak diğer doğrulayıcılar adına çağrı yapabilir. Bu kaynağı almak için CallingAppInfo'nın getOrigin() API'sine ayrıcalıklı ve güvenilir arayanların listesini (JSON biçiminde izin verilenler listesi) iletmeniz gerekir.
val origin = request?.callingAppInfo?.getOrigin(
    privilegedAppsJson // Your allow list JSON
)

Kaynak boş değilse: packageName ve signingInfo'den alınan sertifika parmak izleri, getOrigin() API'sine iletilen izin verilenler listesinde bulunan bir uygulamanın parmak izleriyle eşleşirse kaynak döndürülür. Kaynak değeri alındıktan sonra sağlayıcı uygulama, bunu ayrıcalıklı bir çağrı olarak değerlendirmeli ve kaynağı, çağıran uygulamanın imzası kullanılarak hesaplamak yerine OpenID4VP yanıtında ayarlamalıdır.

Google Şifre Yöneticisi, getOrigin()'ye yapılan aramalar için herkese açık bir izin verilenler listesi kullanır. Kimlik bilgisi sağlayıcı olarak bu listeyi kullanabilir veya API tarafından açıklanan JSON biçiminde kendi listenizi sağlayabilirsiniz. Hangi listenin kullanılacağını sağlayıcı belirler. Üçüncü taraf kimlik bilgisi sağlayıcılarıyla ayrıcalıklı erişim elde etmek için üçüncü tarafın sağladığı belgelere bakın.

Kaynak boşsa doğrulayıcı isteği bir Android uygulamasından geliyordur. OpenID4VP yanıtına yerleştirilecek uygulama kaynağı android:apk-key-hash:<encoded SHA 256 fingerprint> olarak hesaplanmalıdır.

val appSigningInfo = request?.callingAppInfo?.signingInfoCompat?.signingCertificateHistory[0]?.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val certHash = Base64.encodeToString(md.digest(appSigningInfo), Base64.NO_WRAP or Base64.NO_PADDING)
return "android:apk-key-hash:$certHash"

Kart Sahibi kullanıcı arayüzünü oluşturma

Kimlik bilgisi seçildiğinde, kullanıcının uygulama kullanıcı arayüzünde yolunu bulmasına yardımcı olmak için kart sahibi uygulaması çağrılır. Bu iş akışını yönetmenin iki standart yolu vardır:

  • Kimlik bilgilerinin yayınlanması için ek kullanıcı kimlik doğrulaması gerekiyorsa BiometricPrompt API'yi kullanın. Bu durum, örnekte gösterilmektedir.
  • Aksi takdirde, birçok cüzdan, verileri hemen çağıran uygulamaya geri ileten boş bir etkinlik oluşturarak sessiz bir geri dönüşü tercih eder. Bu, kullanıcı tıklamalarını en aza indirir ve daha sorunsuz bir deneyim sağlar.

Kimlik bilgisi yanıtını döndürme

Cüzdan uygulamanız sonucu geri göndermeye hazır olduğunda, kimlik bilgisi yanıtıyla etkinliği tamamlayın:

PendingIntentHandler.setGetCredentialResponse(
    resultData,
    GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()

Bir istisna varsa benzer şekilde kimlik bilgisi istisnası gönderebilirsiniz:

PendingIntentHandler.setGetCredentialException(
    resultData,
    GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()

Bağlam içinde kimlik bilgisi yanıtı döndürmeyle ilgili tam bir örnek için örnek uygulamaya bakın.