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

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

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

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

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

הגיליון התחתון של 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 או יוצרים פרויקט אם עדיין אין לכם פרויקט.
  2. בדף מסך ההסכמה של OAuth, מוודאים שכל המידע מלא ומדויק.
    1. מוודאים שהאפליקציה מוגדרת עם שם, לוגו ודף בית נכונים. הערכים האלה יוצגו למשתמשים במסך ההסכמה לכניסה באמצעות חשבון Google בזמן ההרשמה, ובמסך האפליקציות והשירותים של צד שלישי.
    2. חשוב לוודא שציינתם את כתובות ה-URL של מדיניות הפרטיות ושל התנאים וההגבלות של האפליקציה.
  3. בדף Credentials, יוצרים מזהה לקוח של Android לאפליקציה אם עדיין אין לה מזהה כזה. תצטרכו לציין את שם החבילה ואת החתימה של SHA-1 של האפליקציה.
    1. עוברים אל דף Credentials.
    2. לוחצים על Create credentials (יצירת פרטי כניסה) > OAuth client ID (מזהה לקוח OAuth).
    3. בוחרים את סוג האפליקציה ל-Android.
  4. בדף Credentials, יוצרים מזהה לקוח חדש מסוג Web application, אם עדיין לא עשיתם זאת. בשלב הזה אפשר להתעלם מהשדות 'מקורות 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

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 הזה כדי לאפשר לספק לנקות כל סשן של פרטי כניסה ששמורים.