1. Başlamadan önce
Geleneksel kimlik doğrulama çözümleri, güvenlik ve kullanılabilirlik açısından çeşitli zorlukları beraberinde getirir.
Şifreler yaygın şekilde kullanılıyor ancak...
- Kolayca unutulur
- Güçlü şifreler oluşturmak için kullanıcıların bilgiye ihtiyacı vardır.
- Saldırganlar tarafından kimlik avı yapılması, toplanması ve tekrar oynanması kolaydır.
Android, şifresiz kimlik doğrulama için yeni nesil endüstri standardı olan geçiş anahtarlarını destekleyerek oturum açma deneyimini basitleştirmek ve güvenlik risklerini gidermek için Credential Manager API'yi oluşturdu.
Kimlik Bilgisi Yöneticisi, geçiş anahtarı desteğini bir araya getirir ve şifre veya Google ile oturum açma gibi geleneksel kimlik doğrulama yöntemleriyle birleştirir.
Kullanıcılar geçiş anahtarları oluşturup Google Şifre Yöneticisi'nde saklayabilir. Bu sayede, bu geçiş anahtarları kullanıcının oturum açtığı Android cihazlarla senkronize edilir. Geçiş anahtarının oluşturulması, bir kullanıcı hesabıyla ilişkilendirilmiş ve kullanıcının oturum açabilmesi için ortak anahtarının bir sunucuda saklanması gerekir.
Bu codelab'de, Credential Manager API'den yararlanarak geçiş anahtarları ve şifre kullanarak nasıl kaydolacağınızı ve bunları gelecekteki kimlik doğrulama işlemleri için nasıl kullanacağınızı öğreneceksiniz. Aşağıdakileri içeren 2 akış vardır:
- Kaydolma : geçiş anahtarları ve şifre kullanarak.
- Oturum aç : geçiş anahtarlarını ve kayıtlı şifre.
Ön koşullar
- Android Studio'da uygulamaların nasıl çalıştırılacağına dair temel bilgiler.
- Android uygulamalarındaki kimlik doğrulama akışıyla ilgili temel bilgiler.
- Geçiş anahtarları ile ilgili temel bilgiler
Neler öğreneceksiniz?
- Geçiş anahtarı nasıl oluşturulur?
- Şifre, şifre yöneticisine nasıl kaydedilir?
- Geçiş anahtarı veya kayıtlı şifreyle kullanıcıların kimliğini doğrulama
Gerekenler
Aşağıdaki cihaz kombinasyonlarından biri:
- Android 9 veya sonraki sürümleri (geçiş anahtarları için) ve Android 4.4 veya sonraki sürümleri(Kimlik Bilgisi Yöneticisi API'si aracılığıyla şifre kimlik doğrulaması için) çalıştıran bir Android cihaz.
- Cihaz, tercihen biyometrik sensöre sahip olmalıdır.
- Bir biyometri (veya ekran kilidi) kaydettiğinizden emin olun.
- Kotlin eklentisi sürümü : 1.8.10
2. Hazırlanın
- Bu depoyu dizüstü bilgisayarınızda credman_codelab dalından klonlayın : https://github.com/android/identity-samples/tree/credman_codelab
- CredentialManager modülüne gidin ve projeyi Android Studio'da açın.
Uygulamanın ilk durumuna göz atalım
Uygulamanın ilk durumunun nasıl çalıştığını görmek için aşağıdaki adımları izleyin:
- Uygulamayı başlatın.
- Kaydolma ve oturum açma düğmesinin bulunduğu bir ana ekran görüyorsunuz.
- Geçiş anahtarı veya şifre kullanarak kaydolmak için kaydol seçeneğini tıklayabilirsiniz.
- Geçiş anahtarı ve anahtarı kullanarak oturum açmak için oturum aç kayıtlı şifre.
Geçiş anahtarlarının ne olduğunu ve nasıl çalıştığını anlamak için Geçiş anahtarları nasıl çalışır? başlıklı makaleyi inceleyin. ürün veya hizmetlerin tanıtımını yapıp yapmadığınızı kontrol edin.
3. Geçiş anahtarı kullanarak kaydolma özelliğini ekleyin
Kullanıcılar, Credential Manager API'yi kullanan bir Android uygulamasında yeni bir hesaba kaydolurken hesapları için geçiş anahtarı oluşturabilir. Bu geçiş anahtarı, kullanıcının seçtiği kimlik bilgisi sağlayıcıda güvenli bir şekilde saklanır ve kullanıcının her seferinde şifresini girmesine gerek kalmadan gelecekteki oturum açma işlemlerinde kullanılır.
Şimdi geçiş anahtarı oluşturup kullanıcı kimlik bilgilerini biyometri/ekran kilidi kullanarak kaydedeceksiniz.
Geçiş anahtarıyla kaydolun
Inside Credential Manager (Kimlik Bilgisi Yöneticisi) -> uygulama -> ana -> /Java -> SignUpFragment.kt "kullanıcı adı" metin alanını ve geçiş anahtarıyla kaydolma düğmesi.
createPasskey() çağrısına sorgulamayı ve diğer json yanıtını iletin
Geçiş anahtarı oluşturulmadan önce, sunucudan createCredential() çağrısı sırasında Credential Manager API'ye aktarılacak gerekli bilgileri almasını istemeniz gerekir.
Neyse ki, öğelerinizde(RegFromServer.txt) bu tür parametreleri bu codelab'de döndüren bir örnek yanıtınız zaten var.
- Uygulamanızda SignUpFragment.kt, Find, signUpWithPasskeys yöntemine gidin. Bu yöntemde, geçiş anahtarı oluşturup kullanıcının giriş yapmasına izin verme mantığını yazın. Yöntemi aynı sınıfta bulabilirsiniz.
- createPasskey() işlevini çağırmak için else bloğunu bir yorumla kontrol edin ve aşağıdaki kodla değiştirin :
SignUpFragment.kt
//TODO : Call createPasskey() to signup with passkey
val data = createPasskey()
Bu yöntem, ekranda geçerli bir kullanıcı adı doldurulduğunda çağrılır.
- createPasskey() yönteminin içinde, gerekli parametrelerin döndürülmesiyle birlikte bir CreatePublicKeyCredentialRequest() oluşturmanız gerekir.
SignUpFragment.kt
//TODO create a CreatePublicKeyCredentialRequest() with necessary registration json from server
val request = CreatePublicKeyCredentialRequest(fetchRegistrationJsonFromServer())
Bu fetchRegistrationJsonFromServer(), öğelerden kayıt JSON yanıtını okuyan ve geçiş anahtarı oluşturulurken iletilecek kayıt json'unu döndüren bir yöntemdir.
- publishJsonFromServer() yöntemini bulun, json'u döndürmek için TODO değerini aşağıdaki kodla değiştirin, ayrıca boş dize Return ifadesini kaldırın :
SignUpFragment.kt
//TODO fetch registration mock response
val response = requireContext().readFromAsset("RegFromServer")
//Update userId,challenge, name and Display name in the mock
return response.replace("<userId>", getEncodedUserId())
.replace("<userName>", binding.username.text.toString())
.replace("<userDisplayName>", binding.username.text.toString())
.replace("<challenge>", getEncodedChallenge())
- Burada, öğelerden kayıt json dosyasını okursunuz.
- Bu json dosyasında değiştirilecek 4 alan var.
- Bir kullanıcının birden fazla geçiş anahtarı oluşturabilmesi için (gerekirse) UserId'nin benzersiz olması gerekir. <userId> yeni kullanıcı kimliği oluşturabilirsiniz.
- <challenge> benzersiz olması gerekir. Böylece rastgele ve benzersiz bir görev oluşturabilirsiniz. Bu yöntem zaten kodunuzda mevcut.
Aşağıdaki kod snippet'i, sunucudan aldığınız örnek seçenekleri içerir:
{
"challenge": String,
"rp": {
"name": String,
"id": String
},
"user": {
"id": String,
"name": String,
"displayName": String
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 1800000,
"attestation": "none",
"excludeCredentials": [],
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
Aşağıdaki tabloda olası her örneğe yer verilmemiştir, ancak PublicKeyCredentialCreationOptions
sözlüğündeki önemli parametreler verilmiştir:
Parametreler | Açıklamalar |
Tahmin edilmesini zorlaştıracak kadar entropi içeren, sunucu tarafından oluşturulan rastgele bir dize. En az 16 bayt uzunluğunda olmalıdır. Bu bilgi zorunludur ancak onay yapılmadığı sürece kayıt sırasında kullanılmaz. | |
Kullanıcının benzersiz kimliği. Bu değer, kişisel verileri ifşa edici bilgiler (ör. e-posta adresleri veya kullanıcı adları) içermemelidir. Hesap başına oluşturulan rastgele, 16 baytlık bir değer işe yarayacaktır. | |
Bu alanda, kullanıcının tanıyacağı hesaba ait benzersiz bir tanımlayıcı (ör. e-posta adresi veya kullanıcı adı) bulunmalıdır. Bu, hesap seçicide gösterilir. (Kullanıcı adı kullanıyorsanız şifre kimlik doğrulamasındakiyle aynı değeri kullanın.) | |
Bu alan, hesap için isteğe bağlı ve daha kullanıcı dostu bir addır. Bu, kullanıcı hesabı için insanlar tarafından kullanılabilecek ve yalnızca gösterime yönelik bir addır. | |
Bağlı Taraf Tüzel Kişi, başvuru ayrıntılarınıza karşılık gelir.Şunlar gerekir :
| |
Ortak Anahtar Kimlik Bilgisi Parametreleri, izin verilen algoritmaların ve anahtar türlerinin listesidir. Bu liste en az bir öğe içermelidir. | |
Bir cihazı kaydetmeye çalışan kullanıcının başka cihazları da kayıtlı olabilir. Tek bir kimlik doğrulayıcıda aynı hesap için birden fazla kimlik bilgisi oluşturulmasını sınırlamak amacıyla bu cihazları yoksayabilirsiniz. transports üyesi (sağlanmışsa), her kimlik bilgisinin kaydı sırasında getTransports() çağrısının sonucunu içermelidir. | |
cihazın platforma takılı olup olmaması gerektiğini veya bununla ilgili bir gereklilik olup olmadığını belirtir. "Platform" olarak ayarlayın. Bu, platform cihazına yerleştirilmiş bir kimlik doğrulayıcı istediğimizi ve kullanıcıdan kimlik doğrulayıcıyı eklemesinin istenmeyeceğini (ör. bir USB güvenlik anahtarı var. | |
| "zorunlu" bir değer belirtin kullanabilirsiniz. |
Kimlik bilgisi oluşturun
- CreatePublicKeyCredentialRequest() oluşturduktan sonra oluşturulan istekle birlikte createCredential() çağrısını çağırmanız gerekir.
SignUpFragment.kt
//TODO call createCredential() with createPublicKeyCredentialRequest
try {
response = credentialManager.createCredential(
requireActivity(),
request
) as CreatePublicKeyCredentialResponse
} catch (e: CreateCredentialException) {
configureProgress(View.INVISIBLE)
handlePasskeyFailure(e)
}
- gerekli bilgileri createCredential() çağrısına gönderirsiniz.
- İstek başarılı olduğunda ekranınızda geçiş anahtarı oluşturmanızı isteyen bir alt sayfada görürsünüz.
- Kullanıcılar artık biyometri veya ekran kilidi gibi yöntemlerle kimliklerini doğrulayabilirler.
- Oluşturulan görünümlerin görünürlüğünü siz yönetir ve isteğin herhangi bir nedenden dolayı başarısız olması ya da başarısız olması durumunda istisnaları yönetirsiniz. Burada hata mesajları günlüğe kaydedilir ve uygulamada bir hata iletişim kutusunda gösterilir. Hata günlüklerinin tamamını Android Studio veya adb hata ayıklama komutunu kullanarak kontrol edebilirsiniz.
- Şimdi son olarak, ortak anahtar kimlik bilgisini sunucuya göndererek ve kullanıcının giriş yapmasına izin vererek kayıt işlemini tamamlamanız gerekir. Uygulama, geçiş anahtarını kaydetmek için sunucuya gönderebileceğiniz bir ortak anahtar içeren kimlik bilgisi nesnesi alır.
Burada, bir sahte sunucu kullandık. Dolayısıyla sunucunun gelecekte kimlik doğrulama ve doğrulama amacıyla kaydedilen ortak anahtarı kaydettiğini göstermek için yalnızca true değerini döndürüyoruz.
signUpWithPasskeys() yönteminin içinde ilgili yorumu bulun ve aşağıdaki kodla değiştirin:
SignUpFragment.kt
//TODO : complete the registration process after sending public key credential to your server and let the user in
data?.let {
registerResponse()
DataProvider.setSignedInThroughPasskeys(true)
listener.showHome()
}
- registerResponse, (sahte) sunucunun gelecekte kullanım için ortak anahtarı kaydettiğini gösteren true değerini döndürür.
- setSignInThroughPasskeys işaretini, geçiş anahtarları aracılığıyla giriş yaptığınızı gösterir.
- Giriş yaptıktan sonra kullanıcınızı ana ekrana yönlendirirsiniz.
Aşağıdaki kod snippet'i, almanız gereken örnek seçenekler içerir:
{
"id": String,
"rawId": String,
"type": "public-key",
"response": {
"clientDataJSON": String,
"attestationObject": String,
}
}
Aşağıdaki tabloda olası her örneğe yer verilmemiştir, ancak PublicKeyCredential
içindeki önemli parametreler verilmiştir:
Parametreler | Açıklamalar |
Oluşturulan geçiş anahtarının Base64URL kodlamalı kimliği. Bu kimlik, tarayıcının kimlik doğrulama işleminden sonra cihazda eşleşen bir geçiş anahtarı olup olmadığını belirlemesine yardımcı olur. Bu değer, arka uçtaki veritabanında depolanmalıdır. | |
Kimlik bilgisi kimliğinin | |
| |
|
Uygulamayı çalıştırdığınızda "Geçiş anahtarıyla kaydolun" düğmesini tıklayıp geçiş anahtarı oluşturabilirsiniz.
4. Şifreyi Kimlik Bilgisi Sağlayıcı'ya kaydet
Bu uygulamada, Kaydolma ekranınızda, gösterim amacıyla uygulanmış bir kullanıcı adı ve şifreyle zaten kayıtlısınız.
Kullanıcı şifresi kimlik bilgisini şifre sağlayıcısıyla kaydetmek için, şifreyi kaydetmek amacıyla createCredential() öğesine iletmek için bir CreatePasswordRequest işlemi uygularsınız.
- signUpWithPassword() yöntemini bulun, TODO değerini createPassword çağrısıyla değiştirin :
SignUpFragment.kt
//TODO : Save the user credential password with their password provider
createPassword()
- createPassword() yönteminde şu şekilde bir şifre isteği oluşturmanız gerekir: TODO değerini aşağıdaki kodla değiştirin:
SignUpFragment.kt
//TODO : CreatePasswordRequest with entered username and password
val request = CreatePasswordRequest(
binding.username.text.toString(),
binding.password.text.toString()
)
- Ardından, createPassword() yönteminin içinde, şifre oluşturma isteği ile kimlik bilgisi oluşturmanız ve kullanıcı şifresi kimlik bilgisini kendi şifre sağlayıcısıyla kaydetmeniz, TODO değerini şu kodla değiştirmeniz gerekir :
SignUpFragment.kt
//TODO : Create credential with created password request
try {
credentialManager.createCredential(request, requireActivity()) as CreatePasswordResponse
} catch (e: Exception) {
Log.e("Auth", " Exception Message : " + e.message)
}
- Artık tek dokunuşla şifreyle kimlik doğrulamak için şifre kimlik bilgisini kullanıcının şifre sağlayıcısıyla başarıyla kaydettiniz.
5. Geçiş anahtarı veya şifre ile kimlik doğrulama özelliği ekleyin
Artık bu kimliği uygulamanızda güvenli bir şekilde kimlik doğrulama yöntemi olarak kullanmaya hazırsınız.
getPasskey() çağrısına geçilmesi gereken görevi ve diğer seçenekleri edinin.
Kullanıcıdan kimlik doğrulamasını istemeden önce, sunucudan WebAuthn json dosyasını iletmeye yönelik parametreleri ve bir sorgulamayı istemeniz gerekir.
Öğelerinizde(AuthFromServer.txt) zaten, bu codelab'de bu tür parametreleri döndüren bir taklit yanıtınız var.
- Uygulamanızda, SignInFragment.kt bölümüne gidin.
signInWithSavedCredentials
yöntemini bulun. Burada, kayıtlı geçiş anahtarı veya şifreyle kimlik doğrulamanın mantığını yazdıktan sonra kullanıcının şunları yapmasına izin verebilirsiniz : - createPasskey() işlevini çağırmak için else bloğunu bir yorumla kontrol edin ve aşağıdaki kodla değiştirin :
SignInFragment.kt
//TODO : Call getSavedCredentials() method to signin using passkey/password
val data = getSavedCredentials()
- getSavedCredentials() yönteminde, kimlik bilgisi sağlayıcınızdan kimlik bilgilerini almak için gereken parametreleri içeren bir
GetPublicKeyCredentialOption
() oluşturmanız gerekir.
SigninFragment.kt
//TODO create a GetPublicKeyCredentialOption() with necessary registration json from server
val getPublicKeyCredentialOption =
GetPublicKeyCredentialOption(fetchAuthJsonFromServer(), null)
Bu getAuthJsonFromServer(), öğelerden kimlik doğrulama json yanıtını okuyan ve bu kullanıcı hesabıyla ilişkili tüm geçiş anahtarlarını almak için kimlik doğrulama json'unu döndüren bir yöntemdir.
2. parametre : clientDataHash - bağlı taraf kimliğini doğrulamak için kullanılan bir karmadır. Yalnızca GetCredentialRequest.origin değerini ayarladıysanız ayarlanır. Bu değer, örnek uygulama için boştur.
Uzak kimlik bilgilerini keşfetmek yerine işlemin kullanılabilir kimlik bilgisi olmadığında hemen döndürülmesini tercih ederseniz 3. parametre doğru, aksi takdirde false (varsayılan) değeridir.
- submitAuthJsonFromServer() yöntemini bulun ve TODO değerini aşağıdaki kodla değiştirerek json'u döndürün, ardından boş dize Return ifadesini kaldırın :
SignInFragment.kt
//TODO fetch authentication mock json
return requireContext().readFromAsset("AuthFromServer")
Not : Bu codelab'in sunucusu, API'nin getCredential() çağrısına iletilen PublicKeyCredentialRequestOptions
sözlüğüne olabildiğince benzer bir JSON döndürecek şekilde tasarlanmıştır. Aşağıdaki kod snippet'inde, almanız gereken birkaç örnek seçenek yer almaktadır:
{
"challenge": String,
"rpId": String,
"userVerification": "",
"timeout": 1800000
}
Aşağıdaki tabloda olası her örneğe yer verilmemiştir, ancak PublicKeyCredentialRequestOptions
sözlüğündeki önemli parametreler verilmiştir:
Parametreler | Açıklamalar |
Bir | |
Kısıtlanmış taraf kimliği, alandır. Bir web sitesi, alan adını veya kaydedilebilir bir son eki belirtebilir. Bu değer, geçiş anahtarı oluşturulurken kullanılan |
- Şimdi, bu kullanıcı hesabı için Credential Manager API üzerinden şifre sağlayıcınızda kayıtlı tüm kayıtlı şifreleri almak için bir PasswordOption() nesnesi oluşturmanız gerekir. getSavedCredentials() yönteminin içinde TODO öğesini bulun ve aşağıdakiyle değiştirin :
SigninFragment.kt
//TODO create a PasswordOption to retrieve all the associated user's password
val getPasswordOption = GetPasswordOption()
Kimlik bilgisi alın
- Ardından, ilişkili kimlik bilgilerini almak için yukarıdaki tüm seçeneklerle getCredential() isteğini çağırmanız gerekir :
SignInFragment.kt
//TODO call getCredential() with required credential options
val result = try {
credentialManager.getCredential(
requireActivity(),
GetCredentialRequest(
listOf(
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
} catch (e: Exception) {
configureViews(View.INVISIBLE, true)
Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
activity?.showErrorAlert(
"An error occurred while authenticating through saved credentials. Check logs for additional details"
)
return null
}
if (result.credential is PublicKeyCredential) {
val cred = result.credential as PublicKeyCredential
DataProvider.setSignedInThroughPasskeys(true)
return "Passkey: ${cred.authenticationResponseJson}"
}
if (result.credential is PasswordCredential) {
val cred = result.credential as PasswordCredential
DataProvider.setSignedInThroughPasskeys(false)
return "Got Password - User:${cred.id} Password: ${cred.password}"
}
if (result.credential is CustomCredential) {
//If you are also using any external sign-in libraries, parse them here with the utility functions provided.
}
- Gerekli bilgileri getCredential() çağrısına gönderirsiniz. Bu işlem, alt sayfadaki seçenekleri bu bağlamda oluşturmak için kimlik bilgisi seçeneklerinin listesini ve bir etkinlik bağlamını alır.
- İstek başarılı olduğunda ekranınızda, ilişkili hesap için oluşturulmuş tüm kimlik bilgilerinin listelendiği bir alt sayfada görürsünüz.
- Artık kullanıcılar, seçilen kimlik bilgilerinin kimliğini doğrulamak için biyometri veya ekran kilidi gibi yöntemlerle kimliklerini doğrulayabilir.
- setSignInThroughPasskeys işaretini, geçiş anahtarları aracılığıyla giriş yaptığınızı gösterir. Aksi takdirde false (yanlış) değerini alır.
- Oluşturulan görünümlerin görünürlüğünü siz yönetir ve isteğin herhangi bir nedenden dolayı başarısız olması ya da başarısız olması durumunda istisnaları yönetirsiniz. Burada hata mesajları günlüğe kaydedilir ve uygulamada bir hata iletişim kutusunda gösterilir. Hata günlüklerinin tamamını Android Studio veya adb hata ayıklama komutunu kullanarak kontrol edebilirsiniz.
- Şimdi son olarak, ortak anahtar kimlik bilgisini sunucuya göndererek ve kullanıcının giriş yapmasına izin vererek kayıt işlemini tamamlamanız gerekir. Uygulama, geçiş anahtarı aracılığıyla kimlik doğrulaması yapmak için sunucuya gönderebileceğiniz bir ortak anahtar içeren kimlik bilgisi nesnesi alır.
Burada, bir sahte sunucu kullandık. Dolayısıyla sunucunun ortak anahtarı doğruladığını göstermek üzere true değerini döndürürüz.
signInWithSavedCredentials
() yönteminde ilgili yorumu bulun ve aşağıdaki kodla değiştirin:
SignInFragment.kt
//TODO : complete the authentication process after validating the public key credential to your server and let the user in.
data?.let {
sendSignInResponseToServer()
listener.showHome()
}
- sendSigninResponseToServer(), (sahte) sunucunun gelecekte kullanım için ortak anahtarı doğruladığını gösteren true değerini döndürür.
- Giriş yaptıktan sonra kullanıcınızı ana ekrana yönlendirirsiniz.
Aşağıdaki kod snippet'i örnek bir PublicKeyCredential
nesnesi içerir:
{
"id": String
"rawId": String
"type": "public-key",
"response": {
"clientDataJSON": String
"authenticatorData": String
"signature": String
"userHandle": String
}
}
Aşağıdaki tablo tam kapsamlı değildir ancak PublicKeyCredential
nesnesindeki önemli parametreleri içerir:
Parametreler | Açıklamalar |
Kimliği doğrulanmış geçiş anahtarı kimlik bilgisinin Base64URL kodlamalı kimliği. | |
Kimlik bilgisi kimliğinin | |
İstemci verilerinin | |
Kimlik doğrulayıcı verilerinin | |
İmzanın bir | |
Oluşturma zamanında ayarlanan kullanıcı kimliğini içeren bir |
Uygulamayı çalıştırın, oturum açmak için gidin -> Geçiş anahtarları/kayıtlı şifre ile oturum açıp kayıtlı kimlik bilgilerini kullanarak oturum açmayı deneyin.
Dene
Android uygulamanızda geçiş anahtarı oluşturma, şifreyi Kimlik Bilgisi Yöneticisi'nde kaydetme ve geçiş anahtarları veya kayıtlı şifreler aracılığıyla kimlik doğrulama işlemini Credential Manager API'yi kullanarak uyguladınız.
6. Tebrikler!
Bu codelab'i tamamladınız. Nihai çözünürlüğü https://github.com/android/identity-samples/tree/main/CredentialManager adresinde bulabilirsiniz.
Sorularınız olursa StackOverflow'da passkey
etiketiyle sorabilirsiniz.