Kimlik Bilgisi Yöneticisi'nin Kimlik Bilgisi Aktarımı API'leri, kullanıcı kimlik bilgilerinin kimlik bilgisi sağlayıcılar arasında aynı cihazda güvenli bir şekilde aktarılmasını sağlar. Bu kılavuzda, Android'deki kimlik bilgisi sağlayıcıların androidx.credentials:providerevents kitaplığı tarafından sağlanan API'lerle nasıl entegre edilebileceği ayrıntılı olarak açıklanmaktadır. Bu özellik, standartlaştırılmış FIDO Kimlik Bilgisi Değişim Biçimi'ni (CXF) kullanarak şifreleri, geçiş anahtarlarını, adres bilgilerini ve özel alanları destekler.
Temel kavramlar
Kimlik bilgisi aktarım çerçevesi, ham kimlik bilgilerini Android OS'e veya kimliği doğrulanmamış uygulamalara göstermeden aynı cihazda eşler arası kimlik bilgisi aktarımını kolaylaştırır.
Çerçeve, iki birincil rol tanımlar:
- Dışa aktaran (kaynak sağlayıcı): Kullanıcı kimlik bilgilerini barındıran kimlik bilgisi sağlayıcı. Dışa aktarılabilir hesaplarla (
ExportEntry) ilgili meta verileri sisteme önceden kaydeder ve kullanıcı tarafından seçildiğinde aktarım isteklerine yanıt verir. - İçe aktarıcı (istemci sağlayıcı veya kurulum sihirbazı): Alabileceği kimlik bilgisi ve uzantı türlerini belirterek içe aktarma isteği (
ImportCredentialsRequest) başlatan bir kimlik bilgisi sağlayıcı veya kurulum sihirbazı.
Android sürümü uyumluluğu
Credentials Transfer API, Android 8 (API düzeyi 26) ve sonraki sürümleri çalıştıran cihazlarda kullanılabilir.
Bağımlılık ekleme
Modülünüzün build.gradle veya build.gradle.kts dosyasına androidx.credentials:providerevents bağımlılığını ekleyin:
dependencies {
implementation("androidx.credentials:providerevents:1.0.0-alpha06")
}
Gerekli sınıfı örneklendirme
Gerekli ProviderEventsManager örneğini oluşturun.
val providerEventsManager = ProviderEventsManager.create(context)
Dışa aktarıcıyı uygulama
Kullanıcıların, uygulamanızdaki kimlik bilgilerini cihazdaki diğer kimlik bilgisi sağlayıcılara aktarmasına izin vermek için dışa aktarma rolünü uygulayın.
Dışa aktarma girişlerini kaydetme
Kimlik bilgisi sağlayıcınız değiştiğinde (örneğin, bir kullanıcı oturum açtığında, kimlik bilgileri eklediğinde veya hesapları değiştirdiğinde) ProviderEventsManager.registerExport() kullanarak ExportEntry öğelerinizi kaydedin veya güncelleyin.
Her ExportEntry için gerekenler:
id: Bu dışa aktarma girişini benzersiz şekilde temsil eden, gizli ve rastgele oluşturulmuş bir dize tanımlayıcı. Bu kimliği güvenli bir şekilde saklamanız gerekir. Gelen aktarım isteklerini doğrulamak için daha sonra bu kimliğe ihtiyacınız olacaktır.accountDisplayName: İsteğe bağlı hesap etiketi (örneğin,"Personal Account").userDisplayName: Kullanıcının birincil tanımlayıcısı (örneğin,"alice@example.com").icon: Sağlayıcıyı veya hesabı temsil eden birBitmapsimgesi (kitaplık tarafından otomatik olarak 32x32 PNG boyutuna ölçeklendirilir).supportedCredentialTypes: Bu girişin hangi türleri barındırdığını temsil eden,CredentialTypes'den bir dize sabitleri kümesi.
suspend fun registerMyProviderForExport( providerEventsManager: ProviderEventsManager, providerIcon: Bitmap, // Randomly generated and stored in encrypted storage secretEntryId: String ) { val entry = ExportEntry( id = secretEntryId, accountDisplayName = "MyProvider Personal", userDisplayName = "alice@example.com", icon = providerIcon, supportedCredentialTypes = setOf( CredentialTypes.CREDENTIAL_TYPE_BASIC_AUTH, // Passwords CredentialTypes.CREDENTIAL_TYPE_PUBLIC_KEY, // Passkeys CredentialTypes.CREDENTIAL_TYPE_ADDRESS, CredentialTypes.CREDENTIAL_TYPE_CREDIT_CARD ) ) // RegisterExportRequest.create() attaches the default WASM matcher from assets val request = RegisterExportRequest.create(context, listOf(entry)) try { val response = providerEventsManager.registerExport(request) // Registration successful } catch (e: Exception) { // Handle registration exceptions (e.g., RegisterExportProviderConfigurationException) } }
Dışa aktarma etkinliğini manifest dosyasında bildirme
Kullanıcı, sistem seçici kullanıcı arayüzünde ExportEntry öğenizi seçtiğinde sistem, belirlediğiniz işleme Activity öğesini başlatır. Bu etkinliği zorunlu intent işlemi ve içerik URI şemasıyla bildirin.
Yetkisiz çağrılara ve şaşkın vekil saldırılarına karşı korunmak için Android 14 (API düzeyi 34) ve sonraki sürümlerde android:requireContentUriPermissionFromCaller="write" değerini tanımlayın. Bu, Android işletim sistemine, etkinliğin başlatılmasına izin vermeden önce başlatma işlemini başlatan çağrı yapanın hedef içerik URI'si için yazma izinlerine sahip olduğunu doğrulamasını söyler. Aşağıdaki örnekte gösterildiği gibi:
<activity
android:name="com.example.CredentialExportActivity"
android:exported="true"
android:requireContentUriPermissionFromCaller="write"
android:label="@string/export_activity_label">
<intent-filter>
<!-- This intent action is required for Credential Manager to invoke this activity -->
<action android:name="androidx.identitycredentials.action.IMPORT_CREDENTIALS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
</intent-filter>
</activity>
Etkinliğinizde aktarım amacını işleme
CredentialExportActivity uygulamanızda isteği ayrıştırmak, çağrı yapan bileşeni ve istek meta verilerini doğrulamak, gerekli biyometrik kimlik doğrulamayı gerçekleştirmek ve FIDO CXF yükünü sağlanan içerik URI'sine geri yazmak için IntentHandler.retrieveProviderImportCredentialsRequest(intent) kullanın.
İsteğin kimliğini doğrulama
Etkinliğiniz dışa aktarıldığı için aşağıdaki katmanların her birini doğrulayarak kimlik bilgisi dışa aktarma akışını koruyun:
credIdoturumunun tek seferlik rastgele sayısını doğrulayın (birincil savunma):ExportEntrykaydınızı yaparken kriptografik olarak rastgele, yüksek entropili birid(tek seferlik rastgele sayı) oluşturun ve bunu kısa süreli bir oturumla ilişkilendirin. Etkinliğinizde,request.credIddeğerinin, sağlayıcınız tarafından daha önce verilmiş etkin ve süresi dolmamış bir oturum nonce değeriyle eşleştiğini doğrulayın. Üçüncü taraf uygulamaları bu tek seferlik rastgele sayıyı tahmin edemediğinden, intent'in sistem seçicideki gerçek bir kullanıcı seçimine karşılık gelmesi sağlanır.- Doğrulama
Activity.getCallingPackage()(arayan kontrolü): Kimlik bilgisi seçici, etkinliğinizistartActivityForResultkullanarak başlattığı için etkinliğiniz, kullanıcı arayüzünü başlatan doğrudan arayanın güvenilir sistem kimlik bilgisi seçici çerçevesi (Google Play Hizmetleri'nin bulunduğu Android cihazlarda"com.google.android.gms") olduğunu onaylamak içingetCallingPackage()öğesini inceleyebilir. Arayan paket tanınmıyorsa isteği reddedin. - Inspect
request.callingAppInfo(hedef uygulama bilgileri):callingAppInfo, içe aktarılan kimlik bilgilerini alacak hedef uygulamayı tanımlar. Bu bilgileri şeffaflık için uygun gördüğünüz şekilde (ör. onay kullanıcı arayüzünüzde hedef uygulamanın adını ve simgesini gösterme) veya hedef uygulamanın güvenilir olup olmadığını doğrulamak için kullanabilirsiniz.
class CredentialExportActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 1. Extract the transfer request from the incoming Intent val request: ProviderImportCredentialsRequest? = IntentHandler.retrieveProviderImportCredentialsRequest(intent) if (request == null) { finishWithError() return } // 2. Validate CallingAppInfo and secret `credId` val callingAppPackage = request.callingAppInfo.packageName val receivedCredId = request.credId if (!verifySecretEntryId(receivedCredId) || !isTrustedImporter(callingAppPackage)) { // Secret ID mismatch or untrusted caller -> abort sendExceptionAndFinish(ImportCredentialsNoExportOptionException("Unauthorized request")) return } // 3. Optional: Prompt user for Biometric / PIN authentication before exporting authenticateUserThenExport(request) } private fun authenticateUserThenExport(request: ProviderImportCredentialsRequest) { // ... Biometric prompt logic ... // Once authenticated, generate the FIDO CXF JSON string matching the requested types val cxfJsonPayload = buildFidoCxfJsonPayload( requestedTypes = request.request.credentialTypes, requestedExtensions = request.request.knownExtensions ) val response = ImportCredentialsResponse(cxfJsonPayload) // 4. Write the JSON payload to the Content URI and set Activity result IntentHandler.setImportCredentialsResponse( context = this, uri = request.uri, intent = intent, response = response ) setResult(Activity.RESULT_OK, intent) finish() } private fun sendExceptionAndFinish(exception: androidx.credentials.providerevents.exception.ImportCredentialsException) { IntentHandler.setImportCredentialsException(intent, exception) setResult(Activity.RESULT_OK, intent) finish() } private fun verifySecretEntryId(credentialId: String): Boolean { // Check if credentialId matches what you stored when calling RegisterExportRequest return credentialId == getStoredSecretEntryId() } private fun isTrustedImporter(packageName: String): Boolean { // Implement any specific allowlisting / caller checks if required return true } private fun finishWithError() { setResult(Activity.RESULT_CANCELED) finish() } }
İhracat tescili ve gümrükleme istisnaları
Bu modüldeki tüm istisnalar ImportCredentialsException, RegisterExportException veya ClearExportException alt sınıflarıdır.
RegisterExportProviderConfigurationExceptionveyaClearExportProviderConfigurationException: Sağlayıcı kurulum sorunları (ör.ExportEntryiçinde boşsupportedCredentialTypesveya desteklenmeyen bir işletim sistemi katmanında çağrı yapma) nedeniyle kayıt veya temizleme işlemi başarısız olduğunda oluşturulur.RegisterExportUnknownErrorExceptionveyaClearExportUnknownErrorException: Dışa aktarma kaydı güncellenirken sınıflandırılmamış sistem veya depolama alanı hatası oluştu.
İçe aktarma aracını uygulama
Kimlik bilgilerini uygulamanıza aktarmak için (ör. ilk katılım veya sağlayıcı içe aktarma sırasında) içe aktarma rolünü uygulayın ve ProviderEventsManager.importCredentials() yöntemini çağırarak akışı başlatın.
İçe aktarma isteğini oluşturma ve akışı başlatma
İçe aktarma aracınızın desteklediği CredentialTypes ve KnownExtensions değerlerini belirtin:
suspend fun startCredentialImport( activityContext: Context, providerEventsManager: ProviderEventsManager ) { val importRequest = ImportCredentialsRequest( credentialTypes = setOf( CredentialTypes.CREDENTIAL_TYPE_BASIC_AUTH, CredentialTypes.CREDENTIAL_TYPE_PUBLIC_KEY, CredentialTypes.CREDENTIAL_TYPE_ADDRESS, CredentialTypes.CREDENTIAL_TYPE_NOTE ), knownExtensions = setOf( KnownExtensions.KNOWN_EXTENSION_SHARED ) ) try { // Launches the system Selector UI; suspends until user selects a provider and completes transfer val response = providerEventsManager.importCredentials(activityContext, importRequest) // 1. Inspect the source exporter's package info val exporterPackageName = response.callingAppInfo.packageName // 2. Parse the FIDO CXF JSON string val cxfJsonString = response.response.responseJson parseAndSaveImportedCredentials(cxfJsonString) } catch (e: ImportCredentialsException) { // Handle specific import exceptions (e.g., ImportCredentialsCancellationException) handleImportFailure(e) } } private fun parseAndSaveImportedCredentials(cxfJsonString: String) { val rootJson = JSONObject(cxfJsonString) // Parse according to FIDO Credential Exchange Format (CXF v1.0) specification: // https://fidoalliance.org/specs/cx/cxf-v1.0-ps-20250814.html } // Helper function to make it compile private fun handleImportFailure(e: ImportCredentialsException) {}
Akış istisnalarını içe aktarma
Bu modüldeki tüm istisnalar ImportCredentialsException, RegisterExportException veya ClearExportException alt sınıflarıdır.
ImportCredentialsCancellationException: Kullanıcı, seçici kullanıcı arayüzünü kapattı veya dışa aktarma etkinliğini iptal etti (Activity.RESULT_CANCELED).ImportCredentialsNoExportOptionException: İstenen kimlik bilgisi türleriyle eşleşen kayıtlı dışa aktarma girişi yok veya seçilen dışa aktarma aracı bir ret istisnası oluşturdu.ImportCredentialsProviderConfigurationException: Yapılandırma hatası (ör.ImportCredentialsRequestiçinde boşcredentialTypesayarlanmış veya izinler eksik).ImportCredentialsInvalidJsonException: Dışa aktarma aracı, istek doğrulamasında başarısız olan hatalı biçimlendirilmiş veya boş bir JSON yükü döndürdü.ImportCredentialsSystemErrorException: İçe aktarma sırasında dahili Android sistemi veya Binder aktarım hatası oluştu.ImportCredentialsUnknownCallerException: Arama uygulaması, çerçeve tarafından doğrulanamadı.ImportCredentialsUnknownErrorException: İçe aktarma akışı sırasında sınıflandırılmamış veya beklenmeyen hata.
Desteklenen kimlik bilgisi türleri ve uzantıları
androidx.credentials.providerevents.transfer.CredentialTypes nesnesi, FIDO CXF öğe türlerine karşılık gelen standartlaştırılmış dize sabitlerini tanımlar:
| Sabit | Değer (cxf türü) |
Açıklama |
|---|---|---|
CREDENTIAL_TYPE_BASIC_AUTH |
"basic-auth" |
Kullanıcı adı ve şifre giriş kimlik bilgileri |
CREDENTIAL_TYPE_PUBLIC_KEY |
"passkey" |
FIDO2 veya WebAuthn geçiş anahtarı ortak anahtar kimlik bilgileri. |
CREDENTIAL_TYPE_ADDRESS |
"address" |
Form otomatik doldurma için posta veya kargo adresi bilgileri. |
CREDENTIAL_TYPE_API_KEY |
"api-key" |
API erişim anahtarları ve jetonları |
CREDENTIAL_TYPE_CREDIT_CARD |
"credit-card" |
Kredi ve banka kartı ödeme bilgileri |
CREDENTIAL_TYPE_CUSTOM_FIELDS |
"custom-fields" |
Özel gruplandırmalar veya kullanıcı tanımlı alanlar. |
CREDENTIAL_TYPE_DRIVERS_LICENSE |
"drivers-license" |
Sürücü belgesi bilgileri |
CREDENTIAL_TYPE_FILE |
"file" |
İkili program dosyaları için meta veriler ve yer tutucu referansları. |
CREDENTIAL_TYPE_GENERATED_PASSWORD |
"generated-password" |
Makine tarafından oluşturulan güvenli şifreler. |
CREDENTIAL_TYPE_IDENTITY_DOCUMENT |
"identity-document" |
Resmi kimlik kartları, SSN, Vergi No veya pasaport referansları. |
CREDENTIAL_TYPE_ITEM_REFERENCE |
"item-reference" |
Yükteki başka bir öğeye işaret eden mantıksal bağlantılar. |
CREDENTIAL_TYPE_NOTE |
"note" |
Kullanıcı tarafından tanımlanan güvenli notlar (UTF-8 dizesi). |
CREDENTIAL_TYPE_PASSPORT |
"passport" |
Pasaport seyahat belgesi bilgileri. |
CREDENTIAL_TYPE_PERSON_NAME |
"person-name" |
Kişi kimliği ve adlandırma ayrıntıları. |
CREDENTIAL_TYPE_SSH_KEY |
"ssh-key" |
SSH ortak ve özel anahtar çiftleri. |
CREDENTIAL_TYPE_TOTP |
"totp" |
Zaman tabanlı tek kullanımlık şifre (2FA) gizli anahtarları. |
CREDENTIAL_TYPE_WIFI |
"wifi" |
Kablosuz ağ SSID'si ve parolaları. |
Özel WASM (WebAssembly) eşleştiriciler (Gelişmiş)
Varsayılan olarak, RegisterExportRequest.create(context, entries) çağrıldığında kitaplık öğelerinden sistem varsayılanı credential_transfer_matcher.wasm paketlenir. Bu, girişleri yalnızca supportedCredentialTypes kesişimine göre filtreler.
Kimlik bilgisi sağlayıcınız karmaşık eşleme mantığı gerektiriyorsa (ör. dinamik özellik kontrolleri veya özel alanlara dayalı koşullu filtreleme) WASM kimlik bilgisi aktarım API'siyle eşleşen kendi WebAssembly modülünüzü derleyebilir ve ham bayt dizisini doğrudan iletebilirsiniz:
// Loading a custom WASM matcher val customMatcherBytes = context.assets.open("my_custom_matcher.wasm").use { it.readBytes() } val customRequest = RegisterExportRequest( entries = myEntries, exportMatcher = customMatcherBytes ) providerEventsManager.registerExport(customRequest)