גרסה 2025 רבעון 4: איך מפשטים את תהליכי האימות באמצעות Credential Manager API באפליקציית Android

1. לפני שמתחילים

פתרונות אימות מסורתיים מעלים מספר אתגרים שקשורים לאבטחה ולנוחות השימוש.

סיסמאות נמצאות בשימוש נרחב, אבל…

  • קל לשכוח
  • המשתמשים צריכים לדעת איך ליצור סיסמאות חזקות.
  • קל לנסות לבצע פישינג, לאסוף מידע ולשחזר אותו על ידי תוקפים.

ב-Android פועלים ליצירת Credential Manager API כדי לפשט את חוויית הכניסה ולטפל בסיכוני אבטחה באמצעות תמיכה במפתחות גישה, שהוא תקן התעשייה מהדור הבא לאימות ללא סיסמה.

Credential Manager תומך במפתחות גישה ומשלב אותם עם שיטות אימות מסורתיות כמו סיסמאות, כניסה באמצעות חשבון Google וכו'.

המשתמשים יוכלו ליצור מפתחות גישה, לאחסן אותם במנהל הסיסמאות של Google, ולסנכרן את מפתחות הגישה האלה בין מכשירי Android שבהם המשתמש מחובר. כדי שמשתמש יוכל להיכנס באמצעות מפתח גישה, צריך ליצור אותו, לשייך אותו לחשבון משתמש ולאחסן את המפתח הציבורי שלו בשרת.

ב-codelab הזה תלמדו איך להירשם באמצעות מפתחות גישה וסיסמאות באמצעות Credential Manager API, ואיך להשתמש בהם לצורכי אימות בעתיד. יש 2 תהליכים, כולל:

  • הרשמה : באמצעות מפתחות גישה וסיסמה.
  • כניסה לחשבון : באמצעות מפתחות גישה וסיסמאות שמורות.

דרישות מוקדמות

  • הבנה בסיסית של אופן ההפעלה של אפליקציות ב-Android Studio.
  • הבנה בסיסית של תהליך האימות באפליקציות ל-Android.
  • הבנה בסיסית של מפתחות גישה.

מה תלמדו

  • איך יוצרים מפתח גישה
  • איך שומרים סיסמה במנהל סיסמאות.
  • איך מאמתים משתמשים באמצעות מפתח גישה או סיסמה שמורה.

הדרישות

אחד משילובי המכשירים הבאים:

  • מכשיר Android עם Android מגרסה 9 ואילך (למפתחות גישה) ו-Android מגרסה 4.4 ואילך(לאימות באמצעות סיסמה דרך Credential Manager API).
  • מכשיר, רצוי עם חיישן ביומטרי.
  • חשוב להגדיר שיטה לביטול הנעילה (ביומטרית או אחרת).
  • גרסת הפלאגין של Kotlin : ‏ 1.8.10

2. להגדרה

אפליקציית הדוגמה הזו דורשת קישור נכסים דיגיטליים לאתר כדי שמנהל האישורים יוכל לאמת את הקישור ולהמשיך, ולכן מזהה ה-rp שמשמש בתשובות המדומות הוא משרת מדומיין של צד שלישי. אם רוצים לנסות תגובה מדומה משלכם, אפשר להוסיף את הדומיין של האפליקציה, ולא לשכוח להשלים את הקישור של הנכס הדיגיטלי כמו שמוסבר כאן.

כדי לאמת את הקישור של נכס דיגיטלי של שם החבילה ו-SHA בשרת הדמה, צריך להשתמש באותו debug.keystore שצוין בפרויקט כדי ליצור גרסאות ניפוי באגים וגרסאות הפצה. (הפעולה הזו כבר מתבצעת בשבילכם באפליקציית הדוגמה בקובץ build.gradle).

  1. משכפלים את המאגר הזה במחשב הנייד מהענף credman_codelab: https://github.com/android/identity-samples/tree/credman_codelab
git clone -b credman_codelab https://github.com/android/identity-samples.git
  1. עוברים למודול CredentialManager ופותחים את הפרויקט ב-Android Studio.

הצגת המצב ההתחלתי של האפליקציה

כדי לראות איך המצב הראשוני של האפליקציה פועל, פועלים לפי השלבים הבאים:

  1. מפעילים את האפליקציה.
  2. יוצג מסך ראשי עם לחצני הרשמה וכניסה. הכפתורים האלה עדיין לא עושים כלום, אבל נפעיל את הפונקציונליות שלהם בקטעים הבאים.

7a6fe80f4cf877a8.jpeg

3. הוספת אפשרות להירשם באמצעות מפתחות גישה

כשנרשמים לחשבון חדש באפליקציית Android שמשתמשת ב-Credential Manager API, המשתמשים יכולים ליצור מפתח גישה לחשבון שלהם. מפתח הגישה הזה יישמר בצורה מאובטחת אצל ספק אמצעי הזיהוי שהמשתמש בחר, וישמש לכניסות עתידיות לחשבון בלי שהמשתמש יצטרך להזין את הסיסמה בכל פעם.

עכשיו תיצרו מפתח גישה ותירשמו פרטי כניסה של משתמש באמצעות נתונים ביומטריים או שיטה לפתיחת נעילת המסך.

הרשמה באמצעות מפתח גישה

הקוד בתוך CredentialManager/app/src/main/java/com/google/credentialmanager/sample/SignUpScreen.kt מגדיר שדה טקסט בשם username ולחצן להרשמה באמצעות מפתח גישה.

1f4c50daa2551f1.jpeg

הגדרת פונקציית lambda של createCredential() לשימוש במודלים של תצוגות

אובייקטים של מנהל האישורים דורשים העברה של Activity שמשויך למסך. עם זאת, פעולות במנהל האישורים מופעלות בדרך כלל ב-View Models, ולא מומלץ להפנות אל Activities בתוך View Models. לכן, אנחנו מגדירים את הפונקציות של Credential manager בקובץ נפרד CredentialManagerUtil.kt ומפנים אליהן במסכים המתאימים, שמעבירים אותן לאחר מכן למודלים של התצוגה שלהם כקריאות חוזרות (callbacks) באמצעות פונקציות lambda.

מאתרים את התגובה TODO בפונקציה createCredential() ב-CredentialManagerUtil.kt ומפעילים את הפונקציה CredentialManager.create():

CredentialManagerUtil.kt

suspend fun createCredential(
    activity: Activity,
    request: CreateCredentialRequest
): CreateCredentialResponse {
    TODO("Create a CredentialManager object and call createCredential() with a CreateCredentialRequest")
    val credentialManager = CredentialManager.create(activity)
    return credentialManager.createCredential(activity, request)
}

העברת האתגר ותגובת ה-JSON האחרת לקריאה ל-createPasskey()‎

לפני שיוצרים מפתח גישה, צריך לשלוח לשרת בקשה לקבלת המידע הדרוש להעברה אל Credential Manager API במהלך הקריאה ל-createCredential().

כבר יש לכם נכס בפרויקט שנקרא RegFromServer.txt, שמחזיר את הפרמטרים הנדרשים ב-codelab הזה.

  • באפליקציה, עוברים אל SignUpViewModel.kt, מוצאים את השיטה signUpWithPasskeys שבה תכתבו את הלוגיקה ליצירת מפתח גישה ולאפשר למשתמש להיכנס. אפשר למצוא את השיטה באותה כיתה.
  • מאתרים את בלוק התגובות TODO עד create a CreatePublicKeyCredentialRequest() ומחליפים אותו בקוד הבא:

SignUpViewModel.kt

TODO("Create a CreatePublicKeyCredentialRequest() with necessary registration json from server")
    val request = CreatePublicKeyCredentialRequest(
        jsonProvider.fetchRegistrationJson()
            .replace("<userId>", getEncodedUserId())
            .replace("<userName>", _username.value)
            .replace("<userDisplayName>", _username.value)
            .replace("<challenge>", getEncodedChallenge())
    )

ה-method jsonProvider.fetchRegistrationJsonFromServer() קוראת תגובת JSON של שרת מדומה PublicKeyCredentialCreationOptions מנכסים ומחזירה את ה-JSON של הרישום שיועבר בזמן יצירת מפתח הגישה. אנחנו מחליפים חלק מערכי ה-placeholder בערכים שהמשתמשים מזינים באפליקציה שלנו, ובחלק מהשדות המדומים:

  • קובץ ה-JSON הזה לא מלא, ויש בו 4 שדות שצריך להחליף.
  • מזהה המשתמש צריך להיות ייחודי כדי שמשתמש יוכל ליצור כמה מפתחות גישה (אם נדרש). מחליפים את <userId> בערך userId שנוצר.
  • גם <challenge> צריך להיות ייחודי, ולכן תיצרו אתגר ייחודי אקראי. השיטה כבר קיימת בקוד.

תשובה משרת אמיתי PublicKeyCredentialCreationOptions עשויה להחזיר יותר אפשרויות. דוגמה לחלק מהשדות האלה מופיעה בהמשך:

{
  "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"
  }
}

בטבלה הבאה מוסברים כמה מהפרמטרים החשובים באובייקט PublicKeyCredentialCreationOptions:

פרמטרים

תיאורים

challenge

מחרוזת אקראית שנוצרת על ידי השרת ומכילה מספיק אנטרופיה כדי שלא יהיה אפשר לנחש אותה. האורך שלו צריך להיות לפחות 16 בייט. המאפיין הזה נדרש אבל לא נעשה בו שימוש במהלך הרישום, אלא אם מבצעים אימות.

user.id

מזהה ייחודי של משתמש. הערך הזה לא יכול לכלול פרטים אישיים מזהים, למשל כתובות אימייל או שמות משתמש. ערך אקראי של 16 בייט שנוצר לכל חשבון יתאים.

user.name

בשדה הזה צריך להיות מזהה ייחודי של החשבון שהמשתמש יזהה, כמו כתובת האימייל או שם המשתמש שלו. השם הזה יוצג בבורר החשבונות. (אם משתמשים בשם משתמש, צריך להשתמש באותו ערך כמו באימות באמצעות סיסמה).

user.displayName

השדה הזה הוא אופציונלי, והוא מאפשר להזין שם ידידותי יותר למשתמש לחשבון.

rp.id

הישות של הצד המסתמך תואמת לפרטי האפליקציה שלכם. המאפיינים שלו הם:

  • name (חובה): שם האפליקציה
  • ID (אופציונלי): מתאים לדומיין או לתת-דומיין. אם לא מציינים דומיין, נעשה שימוש בדומיין הנוכחי.
  • icon (אופציונלי).

pubKeyCredParams

רשימה של אלגוריתמים וסוגי מפתחות מותרים. הרשימה הזו חייבת להכיל לפחות רכיב אחד.

excludeCredentials

יכול להיות שהמשתמש שמנסה לרשום מכשיר רשם מכשירים אחרים. כדי להגביל את יצירתם של פרטי כניסה מרובים לאותו חשבון במאמת יחיד, אפשר להתעלם מהמכשירים האלה. אם מסופק חבר transports, הוא צריך להכיל את התוצאה של הקריאה ל-getTransports() במהלך הרישום של כל אישור.

authenticatorSelection.authenticatorAttachment

המדיניות קובעת אם המכשיר צריך להיות מצורף לפלטפורמה, או אם אין דרישה כזו. מגדירים את הערך ל-platform. המשמעות היא שאתם רוצים אמצעי אימות שמוטמע במכשיר של הפלטפורמה, והמשתמש לא יתבקש להכניס למשל מפתח אבטחה USB.

residentKey

מציינים את הערך required כדי ליצור מפתח גישה.

יצירת פרטי כניסה

  1. אחרי שיוצרים CreatePublicKeyCredentialRequest(), צריך להפעיל את הקריאה createCredential() עם הבקשה שנוצרה.

SignUpViewModel.kt

try {
   TODO("Call createCredential() with createPublicKeyCredentialRequest")
   createCredential(request)
   TODO("Complete the registration process after sending public key credential to your server and let the user in")

} catch (e: CreateCredentialException) {
   handlePasskeyFailure(e)
}

  • אתם אחראים לטיפול בחריגים אם הבקשה נכשלת או לא מצליחה מסיבה כלשהי. כאן הודעות השגיאה נרשמות ביומן ומוצגות באפליקציה בתיבת דו-שיח של שגיאה. אפשר לבדוק את יומני השגיאות המלאים דרך Android Studio או הפקודה adb debug.

1ea8ace66135de1e.png

  1. לבסוף, צריך להשלים את תהליך ההרשמה. האפליקציה שולחת אישור מפתח ציבורי לשרת, והשרת רושם אותו למשתמש הנוכחי.

במקרה הזה השתמשנו בשרת מדומה, ולכן אנחנו מחזירים רק את הערך true כדי לציין שהשרת שמר את המפתח הציבורי הרשום למטרות אימות ואימות עתידיות. אפשר לקרוא מידע נוסף על רישום מפתחות גישה בצד השרת כדי להטמיע את התכונה בעצמכם.

בתוך השיטה signUpWithPasskeys(), מוצאים את התגובה הרלוונטית ומחליפים אותה בקוד הבא:

SignUpViewModel.kt

try {
    createCredential(request)
    TODO("Complete the registration process after sending public key credential to your server and let the user in")
registerResponse()
    DataProvider.setSignedInThroughPasskeys(true)
    _navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = true))
} catch (e: CreateCredentialException) {
   handlePasskeyFailure(e)
}
  • הפונקציה registerResponse() מחזירה true, מה שמציין שהמפתח הציבורי נשמר בשרת הדמה לשימוש עתידי.
  • מגדירים את הדגל setSignedInThroughPasskeys לערך true.
  • אחרי שהמשתמש מתחבר, אתם מפנים אותו למסך הבית.

PublicKeyCredential אמיתי עשוי להכיל שדות נוספים. דוגמה לשדות האלה:

{
  "id": String,
  "rawId": String,
  "type": "public-key",
  "response": {
    "clientDataJSON": String,
    "attestationObject": String,
  }
}

בטבלה הבאה מוסברים כמה מהפרמטרים החשובים באובייקט PublicKeyCredential:

פרמטרים

תיאורים

id

מזהה של מפתח הגישה שנוצר בקידוד Base64URL. המזהה הזה עוזר לדפדפן לקבוע אם יש במכשיר מפתח גישה תואם בזמן האימות. הערך הזה צריך להיות מאוחסן במסד הנתונים בקצה העורפי.

rawId

גרסת האובייקט ArrayBuffer של מזהה האישורים.

response.clientDataJSON

אובייקט ArrayBuffer שמכיל נתוני לקוח מקודדים.

response.attestationObject

אובייקט אימות מקודד ArrayBuffer. הוא מכיל מידע חשוב, כמו מזהה RP, דגלים ומפתח ציבורי.

מריצים את האפליקציה, ואז לוחצים על הלחצן הרשמה באמצעות מפתחות גישה ויוצרים מפתח גישה.

4. שמירת סיסמה בספק אישורים

באפליקציה הזו, במסך ההרשמה, כבר הטמענו הרשמה באמצעות שם משתמש וסיסמה למטרות הדגמה.

כדי לשמור את פרטי הכניסה של סיסמת המשתמש אצל ספק הסיסמאות שלו, צריך להטמיע CreatePasswordRequest כדי להעביר אל createCredential() את הסיסמה לשמירה.

  • מחפשים את השיטה signUpWithPassword() ומחליפים את TODO בקריאה ל-createPassword:

SignUpViewModel.kt

TODO("CreatePasswordRequest with entered username and password")
    val passwordRequest = CreatePasswordRequest(_username.value, _password.value)

  • לאחר מכן, יוצרים פרטי כניסה באמצעות בקשה ליצירת סיסמה ושומרים את פרטי הכניסה של סיסמת המשתמש אצל ספק הסיסמאות שלו. לאחר מכן, מתחברים לחשבון של המשתמש. אנחנו מאתרים חריגים שמתרחשים בתהליך הזה באופן כללי יותר. מחליפים את TODO בקוד הבא:

SignUpViewModel.kt

TODO("Create credential with created password request and log the user in")
    try {
        createCredential(passwordRequest)
        simulateServerDelayAndLogIn()
    } catch (e: Exception) {
        val errorMessage = "Exception Message : " + e.message
        Log.e("Auth", errorMessage)
        _passwordCreationError.value = errorMessage
        _isLoading.value = false
    }

עכשיו שמרתם בהצלחה את פרטי הכניסה של הסיסמה אצל ספק הסיסמאות של המשתמש, כדי לבצע אימות באמצעות סיסמה בהקשה אחת בלבד.

5. הוספת אפשרות לאימות באמצעות מפתח גישה או סיסמה

עכשיו אפשר להשתמש בו כדי לאמת את הזהות שלכם באפליקציה בצורה בטוחה.

76e81460b26f9798.png

הגדרת פונקציית lambda ‏getCredential() לשימוש במודלים של תצוגות

כמו קודם, נקרא לפונקציה getCredential() של Credential manager בקובץ נפרד CredentialManagerUtil.kt לצורך הפניה במסכים המתאימים והעברה למודלים של התצוגה שלהם כפונקציות קריאה חוזרת באמצעות פונקציות למדא.

מאתרים את התגובה TODO בפונקציה getCredential() ב-CredentialManagerUtil.kt ומפעילים את הפונקציה CredentialManager.get():

suspend fun getCredential(
    activity: Activity,
    request: GetCredentialRequest
): GetCredentialResponse {
    TODO("Create a CredentialManager object and call getCredential() with a GetCredentialRequest")
    val credentialManager = CredentialManager.create(activity)
    return credentialManager.getCredential(activity, request)
}

קבלת האתגר ואפשרויות אחרות להעברה לקריאה ל-getPasskey()

לפני שמבקשים מהמשתמש לבצע אימות, צריך לבקש מהשרת פרמטרים להעברה ב-WebAuthn JSON, כולל אתגר.

כבר יש לכם תגובה מדומה בנכסים שלכם (AuthFromServer.txt) שמחזירה פרמטרים כאלה ב-codelab הזה.

  • באפליקציה, עוברים אל SignInViewModel.kt, מוצאים את השיטה signInWithSavedCredentials שבה כותבים את הלוגיקה לאימות באמצעות מפתח גישה או סיסמה שמורים, ומאפשרים למשתמש להיכנס:
  • יוצרים GetPublicKeyCredentialOption()‎ עם הפרמטרים הנדרשים כדי לקבל אישורים מספק האישורים.

SignInViewModel.kt

TODO("Create a GetPublicKeyCredentialOption() with necessary authentication json from server")
    val getPublicKeyCredentialOption =
        GetPublicKeyCredentialOption(jsonProvider.fetchAuthJson(), null)

השיטה fetchAuthJsonFromServer() קוראת את תגובת ה-JSON של האימות מנכסים ומחזירה JSON של אימות כדי לאחזר את כל מפתחות הגישה שמשויכים לחשבון המשתמש הזה.

הפרמטר השני של GetPublicKeyCredentialOption()‎ הוא clientDataHash – גיבוב שמשמש לאימות הזהות של הצד הנסמך. מגדירים את הערך הזה רק אם הגדרתם את הערך GetCredentialRequest.origin. באפליקציה לדוגמה, הערך הזה מוגדר ל-null.

הערה : השרת של ה-codelab הזה נועד להחזיר JSON שדומה ככל האפשר למילון PublicKeyCredentialRequestOptions שמועבר לקריאה getCredential() של ה-API. בקטע הקוד הבא יש כמה דוגמאות לאפשרויות שאפשר לקבל בתגובה אמיתית:

{
  "challenge": String,
  "rpId": String,
  "userVerification": "",
  "timeout": 1800000
}

בטבלה הבאה מוסברים כמה מהפרמטרים החשובים באובייקט PublicKeyCredentialRequestOptions:

פרמטרים

תיאורים

challenge

אתגר שנוצר על ידי השרת באובייקט ArrayBuffer. הפעולה הזו נדרשת כדי למנוע מתקפות שליחה מחדש. אל תשתמשו באותו אתגר בתגובה פעמיים. אפשר לחשוב על זה בתור אסימון CSRF.

rpId

מזהה RP הוא דומיין. אתר יכול לציין את הדומיין שלו או סיומת שניתן לרשום. הערך הזה צריך להיות זהה לערך של הפרמטר rp.id שבו השתמשתם כשנוצר מפתח הגישה.

  • לאחר מכן צריך ליצור אובייקט PasswordOption() כדי לאחזר את כל הסיסמאות השמורות שספק הסיסמאות שמר באמצעות Credential Manager API עבור חשבון המשתמש הזה. בתוך getSavedCredentials() method, מחפשים את TODO ומחליפים אותו בקוד הבא:

SigninViewModel.kt

TODO("Create a PasswordOption to retrieve all the associated user's password")

val getPasswordOption = GetPasswordOption()

משלבים את הנתונים האלה לGetCredentialRequest.

SigninViewModel.kt

TODO("Combine requests into a GetCredentialRequest")
    val request = GetCredentialRequest(
        listOf(
            getPublicKeyCredentialOption,
            getPasswordOption
        )
    )

קבלת פרטי כניסה

לאחר מכן צריך לבצע קריאה של בקשת getCredential() עם כל האפשרויות שלמעלה כדי לאחזר את פרטי הכניסה המשויכים:

SignInViewModel.kt

try {
    TODO("Call getCredential() with required credential options")
    val result = getCredential(request)

    val data = when (result.credential) {
        is PublicKeyCredential -> {
            val cred = result.credential as PublicKeyCredential
            DataProvider.setSignedInThroughPasskeys(true)
            "Passkey: ${cred.authenticationResponseJson}"
        }

        is PasswordCredential -> {
            val cred = result.credential as PasswordCredential
            DataProvider.setSignedInThroughPasskeys(false)
            "Got Password - User:${cred.id} Password: ${cred.password}"
        }

        is CustomCredential -> {
            //If you are also using any external sign-in libraries, parse them here with the utility functions provided.
            null
        }

        else -> null
    }

    TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
    } catch (e: Exception) {
        Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
        _signInError.value =
            "An error occurred while authenticating: " + e.message.toString()
    } finally {
        _isLoading.value = false
    }
  • מעבירים את המידע הנדרש אל getCredential(). הפונקציה הזו מקבלת את רשימת האפשרויות של פרטי הכניסה ואת ההקשר של הפעילות כדי להציג את האפשרויות בגיליון התחתון בהקשר הזה.
  • אחרי שהבקשה תעובד בהצלחה, יופיע בחלק התחתון של המסך גיליון עם רשימה של כל פרטי הכניסה שנוצרו לחשבון המשויך.
  • עכשיו המשתמשים יכולים לאמת את הזהות שלהם באמצעות נתונים ביומטריים, שיטה לביטול נעילה וכו', כדי לאמת את פרטי הכניסה שנבחרו.
  • אם פרטי הכניסה שנבחרו הם PublicKeyCredential, מגדירים את הדגל setSignedInThroughPasskeys כ-true. אחרת, מגדירים את הערך false.

קטע הקוד הבא כולל אובייקט לדוגמה PublicKeyCredential:

{
  "id": String
  "rawId": String
  "type": "public-key",
  "response": {
    "clientDataJSON": String
    "authenticatorData": String
    "signature": String
    "userHandle": String
  }
}

הטבלה הבאה לא כוללת את כל הפרמטרים, אבל היא מכילה את הפרמטרים החשובים באובייקט PublicKeyCredential:

פרמטרים

תיאורים

id

המזהה של פרטי הכניסה של מפתח הגישה המאומת בקידוד Base64URL.

rawId

גרסת האובייקט ArrayBuffer של מזהה האישורים.

response.clientDataJSON

אובייקט ArrayBuffer של נתוני לקוחות. השדה הזה מכיל מידע, כמו האתגר והמקור ששרת ה-RP צריך לאמת.

response.authenticatorData

אובייקט ArrayBuffer של נתוני אמצעי האימות. השדה הזה מכיל מידע כמו מזהה RP.

response.signature

אובייקט ArrayBuffer של החתימה. הערך הזה הוא הליבה של פרטי הכניסה וחובה לאמת אותו בשרת.

response.userHandle

אובייקט ArrayBuffer שמכיל את מזהה המשתמש שהוגדר בזמן היצירה. אפשר להשתמש בערך הזה במקום במזהה האישורים אם השרת צריך לבחור את ערכי המזהים שבהם הוא משתמש, או אם ה-Backend רוצה להימנע מיצירת אינדקס של מזהי האישורים.

  • לבסוף, צריך להשלים את תהליך האימות. בדרך כלל, אחרי שהמשתמש משלים את האימות באמצעות מפתח גישה, האפליקציה שולחת לשרת פרטי כניסה של מפתח ציבורי שמכילים טענת אימות. השרת מאמת את הטענה ומאמת את המשתמש.

כאן השתמשנו בשרת מדומה, ולכן אנחנו מחזירים רק true כדי לציין שהשרת אימת את הטענה. אפשר לקרוא מידע נוסף על אימות מפתחות גישה בצד השרת כדי להטמיע את התכונה בעצמכם.

בתוך השיטה signInWithSavedCredentials(), מוצאים את התגובה הרלוונטית ומחליפים אותה בקוד הבא:

SignInViewModel.kt

TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
    if (data != null) {
        sendSignInResponseToServer()
        _navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = DataProvider.isSignedInThroughPasskeys()))
    }
  • sendSigninResponseToServer() מחזירה את הערך true, שמציין שהשרת (המדמה) אימת את המפתח הציבורי לשימוש עתידי.
  • אחרי שהמשתמש מתחבר, אתם מפנים אותו למסך הבית.

מריצים את האפליקציה ועוברים אל כניסה > כניסה באמצעות מפתחות גישה או סיסמה שמורה,ומנסים להיכנס באמצעות פרטי כניסה שמורים.

רוצה לנסות?

הטמעתם באפליקציית Android את היצירה של מפתחות גישה, את שמירת הסיסמה במנהל פרטי הכניסה ואת האימות באמצעות מפתחות גישה או סיסמה שמורה באמצעות Credential Manager API.

6. מעולה!

סיימתם את ה-Codelab הזה! אם רוצים לבדוק את הפתרון הסופי, שזמין בכתובת https://github.com/android/identity-samples/tree/main/CredentialManager

אם יש לכם שאלות, אתם יכולים לשאול אותן ב-StackOverflow עם התג passkey.

מידע נוסף