אימות משתמשים באמצעות כניסה באמצעות חשבון Google

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

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

כדי להגדיר את הכניסה באמצעות חשבון Google, מבצעים את שני השלבים העיקריים הבאים:

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

הגיליון התחתון של Credential Manager
איור 1. ממשק המשתמש לבחירת פרטי הכניסה בגיליון התחתון של Credential Manager

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

אנימציה שמראה את התהליך של הכניסה באמצעות חשבון Google
איור 2. ממשק המשתמש של הלחצן 'כניסה באמצעות חשבון Google' ב-Credential Manager

במסמך הזה נסביר איך לשלב את הלחצן 'כניסה באמצעות חשבון Google' ואת תיבת הדו-שיח התחתונה עם Credential Manager API באמצעות ספריית העזר Google ID.

הגדרת הפרויקט במסוף Google APIs

  1. פותחים את הפרויקט ב-API Console, או יוצרים פרויקט אם עדיין אין לכם פרויקט.
  2. בדף מסך ההסכמה של OAuth, מוודאים שכל המידע מלא ומדויק.
    1. מוודאים שהאפליקציה מוגדרת עם שם, לוגו ודף בית נכונים. הערכים האלה יוצגו למשתמשים במסך ההסכמה של 'כניסה באמצעות חשבון Google' במהלך ההרשמה, ובמסך 'אפליקציות ושירותים של צד שלישי'.
    2. חשוב לוודא שציינתם את כתובות ה-URL של מדיניות הפרטיות ושל התנאים וההגבלות של האפליקציה.
  3. בדף Credentials, יוצרים מזהה לקוח של Android לאפליקציה אם עדיין אין לה מזהה כזה. תצטרכו לציין את שם החבילה ואת החתימה של SHA-1 של האפליקציה.
    1. עוברים אל דף Credentials.
    2. לוחצים על Create credentials (יצירת פרטי כניסה) > OAuth client ID (מזהה לקוח OAuth).
    3. בוחרים את סוג האפליקציה ל-Android.
  4. בדף Credentials, יוצרים מזהה לקוח חדש מסוג 'אפליקציית אינטרנט', אם עדיין לא עשיתם זאת. בשלב הזה אפשר להתעלם מהשדות 'מקורות JavaScript מורשים' ו'מזהי URI להפניה אוטומטית מורשית'. מזהה הלקוח הזה ישמש לזיהוי שרת הקצה העורפי כשהוא יתקשר עם שירותי האימות של Google.
    1. עוברים אל דף Credentials.
    2. לוחצים על Create credentials (יצירת פרטי כניסה) > OAuth client ID (מזהה לקוח OAuth).
    3. בוחרים את סוג אפליקציית האינטרנט.

הצהרת יחסי תלות

בקובץ build.gradle של המודול, מגדירים את יחסי התלות באמצעות הגרסה העדכנית ביותר של Credential Manager:

dependencies {
  // ... other dependencies

  implementation "androidx.credentials:credentials:<latest version>"
  implementation "androidx.credentials:credentials-play-services-auth:<latest version>"
  implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}

יצירת מופע של בקשה לכניסה באמצעות חשבון Google

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

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

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

אם אין חשבונות Google מורשים זמינים, המשתמש יתבקש להירשם באמצעות אחד מהחשבונות הזמינים שלו. כדי לעשות זאת, צריך להציג הודעה למשתמש על ידי קריאה חוזרת ל-API והגדרת setFilterByAuthorizedAccounts לערך false. מידע נוסף על ההרשמה

הפעלת כניסה אוטומטית למשתמשים חוזרים (מומלץ)

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

כדי להפעיל כניסה אוטומטית, משתמשים ב-setAutoSelectEnabled(true). אפשר להיכנס אוטומטית רק אם מתקיימים הקריטריונים הבאים:

  • יש פרטי כניסה יחידים שתואמים לבקשה, שיכולים להיות חשבון Google או סיסמה, ופרטי הכניסה האלה תואמים לחשבון ברירת המחדל במכשיר Android.
  • המשתמש לא יצא מהחשבון באופן מפורש.
  • המשתמש לא השבית את הכניסה האוטומטית בהגדרות של חשבון Google.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

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

הגדרת קוד חד-פעמי (nonce) לשיפור האבטחה

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

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

יצירת התהליך של כניסה באמצעות חשבון Google

כדי להגדיר תהליך כניסה באמצעות חשבון Google:

  1. יוצרים מופע של GetCredentialRequest, ואז מוסיפים את googleIdOption שנוצר קודם באמצעות addCredentialOption() כדי לאחזר את פרטי הכניסה.
  2. מעבירים את הבקשה הזו לקריאה של getCredential() (Kotlin) או getCredentialAsync() (Java) כדי לאחזר את פרטי הכניסה הזמינים של המשתמש.
  3. אחרי שה-API יפעל בהצלחה, מחלצים את CustomCredential שמכיל את התוצאה של נתוני GoogleIdTokenCredential.
  4. הסוג של CustomCredential צריך להיות שווה לערך של GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL. ממירים את האובייקט ל-GoogleIdTokenCredential באמצעות השיטה GoogleIdTokenCredential.createFrom.
  5. אם ההמרה תתבצע בהצלחה, מחלצים את המזהה GoogleIdTokenCredential, מאמתים אותו ומאמתים את פרטי הכניסה בשרת.

  6. אם ההמרה נכשלת עם קוד השגיאה GoogleIdTokenParsingException, יכול להיות שתצטרכו לעדכן את הגרסה של הספרייה של 'כניסה באמצעות חשבון Google'.

  7. לזהות סוגים של פרטי כניסה מותאמים אישית שלא מזוהים.

val request: GetCredentialRequest = Builder()
  .addCredentialOption(googleIdOption)
  .build()

coroutineScope.launch {
  try {
    val result = credentialManager.getCredential(
      request = request,
      context = activityContext,
    )
    handleSignIn(result)
  } catch (e: GetCredentialException) {
    handleFailure(e)
  }
}

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {

    // Passkey credential
    is PublicKeyCredential -> {
      // Share responseJson such as a GetCredentialResponse on your server to
      // validate and authenticate
      responseJson = credential.authenticationResponseJson
    }

    // Password credential
    is PasswordCredential -> {
      // Send ID and password to your server to validate and authenticate.
      val username = credential.id
      val password = credential.password
    }

    // GoogleIdToken credential
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract the ID to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
          // You can use the members of googleIdTokenCredential directly for UX
          // purposes, but don't use them to store or control access to user
          // data. For that you first need to validate the token:
          // pass googleIdTokenCredential.getIdToken() to the backend server.
          GoogleIdTokenVerifier verifier = ... // see validation instructions
          GoogleIdToken idToken = verifier.verify(idTokenString);
          // To get a stable account identifier (e.g. for storing user data),
          // use the subject ID:
          idToken.getPayload().getSubject()
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      } else {
        // Catch any unrecognized custom credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

הפעלת תהליך של לחצן לכניסה באמצעות חשבון Google

כדי להפעיל את תהליך הלחצן 'כניסה באמצעות חשבון Google', משתמשים ב-GetSignInWithGoogleOption במקום ב-GetGoogleIdOption:

val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder()
  .setServerClientId(WEB_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

מטפלים ב-GoogleIdTokenCredential המוחזר כפי שמתואר בדוגמה הבאה לקוד.

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract id to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      }
      else -> {
        // Catch any unrecognized credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

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

מאפשרים הרשמה של משתמשים חדשים (מומלץ)

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

אם לא נמצאו פרטי כניסה שמורים (לא חזרו חשבונות Google על ידי getGoogleIdOption), מבקשים מהמשתמש להירשם. קודם כול, בודקים את הערך של setFilterByAuthorizedAccounts(true) כדי לראות אם יש חשבונות שהשתמשתם בהם בעבר. אם לא נמצאו כאלה, מבקשים מהמשתמש להירשם באמצעות חשבון Google שלו באמצעות setFilterByAuthorizedAccounts(false)

דוגמה:

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(false)
  .setServerClientId(WEB_CLIENT_ID)
  .build()

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

טיפול ביציאה

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

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