האפשרות 'כניסה לחשבון מקושר' מאפשרת למשתמשים להשתמש בכניסה בלחיצה אחת באמצעות Google שכבר מקושר לחשבון Google שלהם לשירות שלכם. כך החוויה של המשתמשים משתפרת, כי הם יכולים להיכנס לחשבון בלחיצה אחת, בלי להזין שוב את שם המשתמש והסיסמה. כמו כן, הוא מפחית את הסיכויים שמשתמשים חשבונות כפולים בשירות שלכם.
הכניסה לחשבון המקושר זמינה כחלק מתהליך הכניסה בהקשה אחת עבור Android. כלומר, אין צורך לייבא ספרייה נפרדת אם האפליקציה התכונה 'הקשה אחת' כבר מופעלת.
במסמך הזה נסביר איך לשנות את אפליקציית Android כך שתתמוך כניסה לחשבון מקושר.
איך זה עובד
- הבעת הסכמה להצגת חשבונות מקושרים בתהליך הכניסה בהקשה אחת.
- אם המשתמש נכנס לחשבון Google וקישר את חשבון Google שלו אל את החשבון שלו בשירות שלכם, יוחזר אסימון מזהה עבור חשבון.
- המשתמש מקבל בקשה להיכנס באמצעות הקשה אחת, עם אפשרות להיכנס לשירות באמצעות החשבון המקושר שלו.
- אם המשתמש בוחר להמשיך עם החשבון המקושר, האסימון המזהה שלו מוחזר לאפליקציה. את ההתאמה הזו שייכת לאסימון שנשלח אל השרת בשלב 2 כדי לזהות את המשתמש המחובר.
הגדרה
הגדרת סביבת הפיתוח
אפשר לקבל את הגרסה העדכנית ביותר של Google Play Services אצל מארח הפיתוח:
- פותחים את Android SDK Manager.
בקטע SDK Tools, מאתרים את Google Play Services.
אם הסטטוס של החבילות האלה הוא 'לא מותקן', בחר את שתי החבילות ולוחצים על Install Pacakge (התקנת חבילות).
הגדרת האפליקציה
בקובץ
build.gradle
ברמת הפרויקט, צריך לכלול את מאגר Maven של Google גם בקטעbuildscript
וגם בקטעallprojects
.buildscript { repositories { google() } } allprojects { repositories { google() } }
מוסיפים את יחסי התלות של ה-API 'קישור ל-Google' לקובץ ה-Gradle ברמת האפליקציה של המודול, שבדרך כלל הוא
app/build.gradle
:dependencies { implementation 'com.google.android.gms:play-services-auth:21.2.0' }
שינוי האפליקציה ל-Android כך שתתמוך בכניסה לחשבון מקושר
בסוף תהליך הכניסה לחשבון המקושר, אסימון מזהה מוחזר לאפליקציה. צריך לאמת את תקינות האסימון המזהה לפני שמכניסים את המשתמש.
בקוד לדוגמה הבא מפורטים השלבים לאחזור, אימות האסימון המזהה ולאחר מכן כניסה של המשתמש.
יצירת פעילות לקבלת התוצאה של כוונת הכניסה
Kotlin
private val activityResultLauncher = registerForActivityResult( ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode == RESULT_OK) { try { val signInCredentials = Identity.signInClient(this) .signInCredentialFromIntent(result.data) // Review the Verify the integrity of the ID token section for // details on how to verify the ID token verifyIdToken(signInCredential.googleIdToken) } catch (e: ApiException) { Log.e(TAG, "Sign-in failed with error code:", e) } } else { Log.e(TAG, "Sign-in failed") } }
Java
private final ActivityResultLauncher<IntentSenderResult> activityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), result -> { If (result.getResultCode() == RESULT_OK) { try { SignInCredential signInCredential = Identity.getSignInClient(this) .getSignInCredentialFromIntent(result.getData()); verifyIdToken(signInCredential.getGoogleIdToken()); } catch (e: ApiException ) { Log.e(TAG, "Sign-in failed with error:", e) } } else { Log.e(TAG, "Sign-in failed") } });
פיתוח הבקשה לכניסה לחשבון
Kotlin
private val tokenRequestOptions = GoogleIdTokenRequestOptions.Builder() .supported(true) // Your server's client ID, not your Android client ID. .serverClientId(getString("your-server-client-id") .filterByAuthorizedAccounts(true) .associateLinkedAccounts("service-id-of-and-defined-by-developer", scopes) .build()
Java
private final GoogleIdTokenRequestOptions tokenRequestOptions = GoogleIdTokenRequestOptions.Builder() .setSupported(true) .setServerClientId("your-service-client-id") .setFilterByAuthorizedAccounts(true) .associateLinkedAccounts("service-id-of-and-defined-by-developer", scopes) .build()
הפעלת הכוונה 'המתנה לכניסה'
Kotlin
Identity.signInClient(this) .beginSignIn( BeginSignInRequest.Builder() .googleIdTokenRequestOptions(tokenRequestOptions) .build()) .addOnSuccessListener{result -> activityResultLauncher.launch(result.pendingIntent.intentSender) } .addOnFailureListener {e -> Log.e(TAG, "Sign-in failed because:", e) }
Java
Identity.getSignInClient(this) .beginSignIn( BeginSignInRequest.Builder() .setGoogleIdTokenRequestOptions(tokenRequestOptions) .build()) .addOnSuccessListener(result -> { activityResultLauncher.launch( result.getPendingIntent().getIntentSender()); }) .addOnFailureListener(e -> { Log.e(TAG, "Sign-in failed because:", e); });
אימות תקינות האסימון המזהה
כדי לוודא שהאסימון חוקי, צריך לוודא את הפרטים הבאים קריטריונים:
- האסימון המזהה חתום כראוי על ידי Google. שימוש במפתחות הציבוריים של Google
(זמין ב:
JWK או
פורמט PEM)
כדי לאמת את החתימה של האסימון. המפתחות האלה עוברים רוטציה באופן קבוע. בדיקה
הכותרת
Cache-Control
בתגובה כדי לקבוע מתי צריך לאחזר אותן שוב. - הערך של
aud
באסימון המזהה שווה לאחד מהערכים של האפליקציה מזהי לקוח. הבדיקה הזו נחוצה כדי למנוע אסימונים מזהים שהונפקו על ידי תוכנה זדונית שמשמשות לגישה לנתונים על אותו משתמש בשרת הקצה העורפי של האפליקציה. - הערך של
iss
באסימון המזהה שווה ל-accounts.google.com
אוhttps://accounts.google.com
. - מועד התפוגה (
exp
) של האסימון המזהה לא עבר. - אם אתם צריכים לאמת שהאסימון המזהה מייצג Google Workspace או Cloud
חשבון ארגוני, אפשר לבדוק את ההצהרה
hd
, שמציינת את המארח הדומיין של המשתמש. צריך להשתמש באפשרות הזו כשמגבילים את הגישה למשאב רק לחברים בדומיין דומיינים מסוימים. היעדר תביעה זו מצביע על כך שהחשבון לא שייך דומיין באירוח Google.
באמצעות השדות email
, email_verified
ו-hd
אפשר לקבוע אם
Google מארחת כתובת אימייל מסוימת, והיא מהימן. במקרים שבהם Google היא גורם מוסמך,
ידוע שהמשתמש הוא הבעלים החוקיים של החשבון, תוכל לדלג על הזנת סיסמה
שיטות לאתגר.
מקרים שבהם Google היא מהימן:
- ל-
email
יש סיומת@gmail.com
. זהו חשבון Gmail. email_verified
מוגדר כ-True ו-hd
מוגדר. זהו חשבון G Suite.
משתמשים יכולים להירשם לחשבונות Google בלי להשתמש ב-Gmail או ב-G Suite. מתי
email
לא מכיל סיומת @gmail.com
ו-hd
חסר, Google אינה
מומלץ לאמת סיסמה או סיסמה או שיטות אחרות לאימות
למשתמש. email_verified
יכול להיות גם נכון כי Google אימתה בהתחלה את
משתמש כשחשבון Google נוצר, אבל בעלות על הצד השלישי
ייתכן שחשבון האימייל השתנה מאז.
במקום לכתוב קוד משלכם כדי לבצע את שלבי האימות האלה, אנחנו ממליצים
מומלץ להשתמש בספריית לקוח של Google API עבור הפלטפורמה שלך, או לשימוש כללי
JWT. לצורכי פיתוח וניפוי באגים, אפשר להתקשר אל tokeninfo
נקודת קצה לאימות.
שימוש בספריית לקוח של Google API
באמצעות ספריית הלקוח של Java Google API היא הדרך המומלצת לאימות אסימונים מזהים של Google בסביבת הייצור.
Java
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
...
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
// Specify the CLIENT_ID of the app that accesses the backend:
.setAudience(Collections.singletonList(CLIENT_ID))
// Or, if multiple clients access the backend:
//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
.build();
// (Receive idTokenString by HTTPS POST)
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
} else {
System.out.println("Invalid ID token.");
}
השיטה GoogleIdTokenVerifier.verify()
מאמתת את החתימה של JWT, את ההצהרה aud
, את ההצהרה iss
ואת ההצהרה exp
.
אם אתם צריכים לאמת שהאסימון המזהה מייצג Google Workspace או Cloud
חשבון ארגוני, אפשר לאמת את הצהרת הזמן לתפוגה hd
על ידי בדיקת שם הדומיין
שהוחזרו באמצעות השיטה Payload.getHostedDomain()
.
קריאה לנקודת הקצה של Tokeninfo
דרך קלה לאמת חתימה של אסימון מזהה לצורך ניפוי באגים היא
משתמשים בנקודת הקצה tokeninfo
. קריאה לנקודת הקצה הזו כוללת
בקשת רשת נוספת שמבצעת את רוב האימות עבורכם בזמן שאתם בודקים
אימות וחילוץ מטען ייעודי (payload) בקוד שלכם. הוא לא מתאים לשימוש בסביבת ייצור
יכול להיות שבקשות עשויות להיות מווסתות או מושפעות משגיאות המתרחשות לסירוגין.
כדי לאמת אסימון מזהה באמצעות נקודת הקצה tokeninfo
, צריך ליצור HTTPS
בקשת POST או GET לנקודת הקצה ומעבירים את האסימון המזהה
id_token
.
לדוגמה, כדי לאמת את האסימון "XYZ123", שולחים את בקשת ה-GET הבאה:
https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123
אם האסימון חתום כראוי והשדות iss
ו-exp
להצהרות יש את הערכים המצופים, תקבלו תגובת HTTP 200,
מכיל את ההצהרות של אסימון מזהה בפורמט JSON.
זוהי דוגמה לתשובה:
{ // These six fields are included in all Google ID Tokens. "iss": "https://accounts.google.com", "sub": "110169484474386276334", "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "iat": "1433978353", "exp": "1433981953", // These seven fields are only included when the user has granted the "profile" and // "email" OAuth scopes to the application. "email": "testuser@gmail.com", "email_verified": "true", "name" : "Test User", "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg", "given_name": "Test", "family_name": "User", "locale": "en" }
אם אתם צריכים לוודא שהאסימון המזהה מייצג חשבון Google Workspace, אתם יכולים לבדוק
ההצהרה hd
, שמציינת את הדומיין המתארח של המשתמש. חובה להשתמש באפשרות הזו כאשר
הגבלת הגישה למשאב רק לחברים בדומיינים מסוימים. היעדר תביעה זו
מציין שהחשבון לא שייך לדומיין מתארח ב-Google Workspace.