משתמשים בלקוח הכניסה בלחיצה אחת כדי לבקש מהמשתמש הרשאה לאחזר את אחד מפרטי הכניסה שבהם הוא השתמש בעבר כדי להיכנס לאפליקציה. פרטי הכניסה האלה יכולים להיות חשבון Google או שילוב של שם משתמש וסיסמה שהמשתמש שמר ב-Google באמצעות מילוי אוטומטי ב-Chrome או ב-Android או באמצעות Smart Lock לסיסמאות.
אחרי שמאחזרים את פרטי הכניסה בהצלחה, אפשר להשתמש בהם כדי לאפשר למשתמש להיכנס לאפליקציה בלי בעיות.
אם המשתמש לא שמר פרטי כניסה, לא מוצג ממשק משתמש, ואפשר לספק את חוויית השימוש הרגילה למשתמשים שלא מחוברים לחשבון.
איפה כדאי להשתמש בכניסה בהקשה אחת?
אם האפליקציה שלכם דורשת מהמשתמשים להיכנס לחשבון, עליכם להציג את ממשק המשתמש של הכניסה בלחיצה אחת במסך הכניסה. התכונה הזו יכולה להיות שימושית גם אם כבר יש לכם לחצן 'כניסה באמצעות חשבון Google': אפשר להגדיר את ממשק המשתמש של One Tap כך שיוצגו רק פרטי הכניסה שהמשתמש השתמש בהם בעבר כדי להיכנס. כך, אם משתמשים נכנסים לאפליקציה שלכם לעיתים רחוקות, הם יכולים להיעזר בזה כדי לזכור איך הם נכנסו בפעם האחרונה, ולא ליצור בטעות חשבונות חדשים באפליקציה.
אם הכניסה לחשבון היא אופציונלית באפליקציה שלכם, כדאי להשתמש בכניסה בהקשה אחת בכל מסך שבו הכניסה לחשבון משפרת את חוויית המשתמש. לדוגמה, אם משתמשים יכולים לעיין בתוכן באפליקציה שלכם כשהם לא מחוברים, אבל הם יכולים לפרסם תגובות או להוסיף פריטים לעגלת קניות רק אחרי שהם מתחברים, זה יהיה הקשר המתאים לשימוש בתכונה 'התחברות בלחיצה אחת'.
גם אפליקציות שבהן הכניסה היא אופציונלית צריכות להשתמש בכניסה בהקשה אחת במסכי הכניסה שלהן, מהסיבות שצוינו למעלה.
לפני שמתחילים
- מגדירים את הפרויקט ב-Google APIs Console ואת פרויקט Android כמו שמתואר במאמר תחילת העבודה עם כניסה בלחיצה אחת.
- אם אתם תומכים בכניסה באמצעות סיסמה, כדאי לבצע אופטימיזציה של האפליקציה למילוי אוטומטי (או להשתמש ב-Smart Lock לסיסמאות) כדי שהמשתמשים יוכלו לשמור את פרטי הסיסמה שלהם אחרי הכניסה.
1. הגדרת לקוח לכניסה בהקשה אחת
אתם יכולים להגדיר את לקוח הכניסה בלחיצה אחת כך שהמשתמשים יוכלו להיכנס באמצעות סיסמאות שמורות, חשבונות Google שמורים או כל אחת מהאפשרויות האלה. (מומלץ לתמוך בשניהם כדי לאפשר למשתמשים חדשים ליצור חשבון בלחיצה אחת, ולמשתמשים חוזרים להתחבר אוטומטית או בלחיצה אחת לכמה שיותר אפליקציות).
אם האפליקציה שלכם משתמשת בכניסה מבוססת-סיסמה, צריך להשתמש ב-setPasswordRequestOptions() כדי להפעיל בקשות לאישורי סיסמה.
אם האפליקציה שלכם משתמשת בכניסה באמצעות חשבון Google, אתם צריכים להשתמש ב-setGoogleIdTokenRequestOptions() כדי להפעיל ולהגדיר בקשות לאסימון מזהה Google:
מגדירים את מזהה הלקוח של השרת למזהה שיצרתם ב-Google APIs Console. שימו לב שזה מזהה הלקוח של השרת, ולא מזהה הלקוח של Android.
מגדירים את הלקוח כך שיסנן לפי חשבונות מורשים. כשמפעילים את האפשרות הזו, לקוחות One Tap מציגים למשתמשים רק חשבונות Google שהם כבר השתמשו בהם בעבר כדי להיכנס לאפליקציה. הוספת האפשרות הזו יכולה לעזור למשתמשים להיכנס בהצלחה לאפליקציה אם הם לא בטוחים אם כבר יש להם חשבון או באיזה חשבון Google הם השתמשו, והיא מונעת מהמשתמשים ליצור בטעות חשבונות חדשים באפליקציה שלכם.
אם רוצים שהמשתמשים ייכנסו לחשבון באופן אוטומטי כשאפשר, צריך להפעיל את התכונה באמצעות
setAutoSelectEnabled(). אפשר להיכנס לחשבון באופן אוטומטי אם מתקיימים הקריטריונים הבאים:- למשתמש יש בדיוק פרט גישה אחד שמור לאפליקציה שלכם. כלומר, סיסמה שמורה אחת או חשבון Google שמור אחד.
- המשתמש לא השבית את הכניסה האוטומטית בהגדרות חשבון Google.
אמנם השימוש בצופן חד-פעמי (nonce) הוא אופציונלי, אבל מומלץ מאוד להשתמש בו כדי לשפר את אבטחת הכניסה ולמנוע מתקפות חוזרות. כדי לכלול nonce בכל בקשה, משתמשים ב-setNonce. הצעות ופרטים נוספים על יצירת מספר חד-פעמי מופיעים בקטע קבלת מספר חד-פעמי במאמר בנושא SafetyNet.
Java
public class YourActivity extends AppCompatActivity { // ... private SignInClient oneTapClient; private BeginSignInRequest signInRequest; @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); oneTapClient = Identity.getSignInClient(this); signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.default_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build(); // ... } // ... }
Kotlin
class YourActivity : AppCompatActivity() { // ... private lateinit var oneTapClient: SignInClient private lateinit var signInRequest: BeginSignInRequest override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) oneTapClient = Identity.getSignInClient(this) signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions( BeginSignInRequest.GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.your_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build() // ... } // ... }
2. בדיקה אם משתמש מחובר לחשבון
אם משתמש מחובר או משתמש לא מחובר יכולים להשתמש בפעילות שלכם, צריך לבדוק את הסטטוס של המשתמש לפני שמציגים את ממשק הכניסה בלחיצה אחת.
כדאי גם לעקוב אחרי המקרים שבהם המשתמש כבר סירב להשתמש בכניסה בלחיצה אחת, למשל אם הוא סגר את ההנחיה או הקשה מחוץ לה. זה יכול להיות פשוט כמו מאפיין בוליאני של הפעילות. (ראו הפסקת הצגת ממשק המשתמש של 'לחיצה אחת' בהמשך).
3. הצגת ממשק המשתמש של התחברות בלחיצה אחת
אם המשתמש לא מחובר לחשבון ולא דחה בעבר את השימוש בכניסה בלחיצה אחת, צריך לקרוא לשיטה beginSignIn() של אובייקט הלקוח ולצרף מאזינים ל-Task שהיא מחזירה. בדרך כלל האפליקציות עושות את זה בשיטה onCreate() של Activity
או אחרי מעברים בין מסכים כשמשתמשים בארכיטקטורה של Activity יחיד.
אם למשתמש יש פרטי כניסה שמורים לאפליקציה שלכם, לקוח One Tap יפעיל את מאזין ההצלחה. במאזין ההצלחה, צריך לקבל את הכוונה התלויה ועומדת מתוצאת Task ולהעביר אותה אל startIntentSenderForResult() כדי להפעיל את ממשק המשתמש של הכניסה באמצעות One Tap.
אם למשתמש אין פרטי כניסה שמורים, לקוח לחיצה אחת יפעיל את מאזין הכשל. במקרה כזה, לא צריך לבצע שום פעולה: אפשר פשוט להמשיך להציג את חוויית השימוש באפליקציה ללא חיבור לחשבון. עם זאת, אם אתם תומכים בהרשמה בלחיצה אחת, תוכלו להתחיל את התהליך הזה כאן כדי ליצור חשבון בצורה חלקה. איך יוצרים חשבונות חדשים בהקשה אחת
Java
oneTapClient.beginSignIn(signUpRequest)
.addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
@Override
public void onSuccess(BeginSignInResult result) {
try {
startIntentSenderForResult(
result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.getLocalizedMessage());
}
});
Kotlin
oneTapClient.beginSignIn(signInRequest)
.addOnSuccessListener(this) { result ->
try {
startIntentSenderForResult(
result.pendingIntent.intentSender, REQ_ONE_TAP,
null, 0, 0, 0, null)
} catch (e: IntentSender.SendIntentException) {
Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
.addOnFailureListener(this) { e ->
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.localizedMessage)
}
4. טיפול בתשובה של המשתמש
התשובה של המשתמש להנחיה לכניסה בלחיצה אחת תדווח לאפליקציה באמצעות השיטה onActivityResult() של הפעילות. אם המשתמש בחר להיכנס לחשבון, התוצאה תהיה פרטי כניסה שנשמרו. אם המשתמש סירב להיכנס, על ידי סגירת ממשק המשתמש של הכניסה בלחיצה אחת או הקשה מחוצה לו, התוצאה תוחזר עם הקוד RESULT_CANCELED. האפליקציה צריכה לטפל בשני המקרים האלה.
כניסה באמצעות פרטי כניסה שאוחזרו
אם המשתמש בחר לשתף את פרטי הכניסה עם האפליקציה שלכם, תוכלו לאחזר אותם על ידי העברת נתוני הכוונה מ-onActivityResult() לשיטה getSignInCredentialFromIntent() של לקוח One Tap. למאפיין googleIdToken של פרטי הכניסה יהיה ערך שאינו null אם המשתמש שיתף פרטי כניסה לחשבון Google עם האפליקציה שלכם, או ערך שאינו null למאפיין password אם המשתמש שיתף סיסמה שמורה.
משתמשים באמצעי האימות כדי לבצע אימות עם קצה העורפי של האפליקציה.
- אם אוחזרו שם משתמש וסיסמה, משתמשים בהם כדי להיכנס לחשבון באותו אופן שבו נכנסים אם המשתמש סיפק אותם באופן ידני.
אם אוחזרו פרטי כניסה לחשבון Google, משתמשים בטוקן הזהות כדי לבצע אימות עם ה-backend. אם בחרתם להשתמש בערך חד-פעמי כדי למנוע מתקפות שידור חוזר, בדקו את ערך התגובה בשרת העורפי. אפשר לעיין במאמר בנושא אימות באמצעות קצה עורפי באמצעות אסימוני מזהה.
Java
public class YourActivity extends AppCompatActivity { // ... private static final int REQ_ONE_TAP = 2; // Can be any integer unique to the Activity. private boolean showOneTapUI = true; // ... @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQ_ONE_TAP: try { SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data); String idToken = credential.getGoogleIdToken(); String username = credential.getId(); String password = credential.getPassword(); if (idToken != null) { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token."); } else if (password != null) { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password."); } } catch (ApiException e) { // ... } break; } } }
Kotlin
class YourActivity : AppCompatActivity() { // ... private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity private var showOneTapUI = true // ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { REQ_ONE_TAP -> { try { val credential = oneTapClient.getSignInCredentialFromIntent(data) val idToken = credential.googleIdToken val username = credential.id val password = credential.password when { idToken != null -> { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token.") } password != null -> { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password.") } else -> { // Shouldn't happen. Log.d(TAG, "No ID token or password!") } } } catch (e: ApiException) { // ... } } } } // ... }
הפסקת ההצגה של ממשק המשתמש של התחברות בלחיצה אחת
אם המשתמש דחה את הכניסה, הקריאה ל-getSignInCredentialFromIntent() תחזיר ApiException עם קוד סטטוס CommonStatusCodes.CANCELED.
במצב כזה, כדאי להשבית באופן זמני את ממשק המשתמש של הכניסה בלחיצה אחת כדי לא להציק למשתמשים עם הנחיות חוזרות. בדוגמה הבאה, כדי להשיג את המטרה הזו, מוגדר מאפיין בפעילות, שמשמש לקביעה אם להציע למשתמש כניסה בלחיצה אחת. עם זאת, אפשר גם לשמור ערך ב-SharedPreferences או להשתמש בשיטה אחרת.
חשוב להטמיע הגבלת קצב משלכם להצגת הנחיות לכניסה בהקשה אחת. אם לא תעשו זאת, ומשתמש יבטל כמה הנחיות ברצף, לקוח לחיצה אחת לא יציג למשתמש הנחיות במשך 24 השעות הבאות.
Java
public class YourActivity extends AppCompatActivity { // ... private static final int REQ_ONE_TAP = 2; // Can be any integer unique to the Activity. private boolean showOneTapUI = true; // ... @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQ_ONE_TAP: try { // ... } catch (ApiException e) { switch (e.getStatusCode()) { case CommonStatusCodes.CANCELED: Log.d(TAG, "One-tap dialog was closed."); // Don't re-prompt the user. showOneTapUI = false; break; case CommonStatusCodes.NETWORK_ERROR: Log.d(TAG, "One-tap encountered a network error."); // Try again or just ignore. break; default: Log.d(TAG, "Couldn't get credential from result." + e.getLocalizedMessage()); break; } } break; } } }
Kotlin
class YourActivity : AppCompatActivity() { // ... private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity private var showOneTapUI = true // ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { REQ_ONE_TAP -> { try { // ... } catch (e: ApiException) { when (e.statusCode) { CommonStatusCodes.CANCELED -> { Log.d(TAG, "One-tap dialog was closed.") // Don't re-prompt the user. showOneTapUI = false } CommonStatusCodes.NETWORK_ERROR -> { Log.d(TAG, "One-tap encountered a network error.") // Try again or just ignore. } else -> { Log.d(TAG, "Couldn't get credential from result." + " (${e.localizedMessage})") } } } } } } // ... }
5. טיפול ביציאה מהחשבון
כשמשתמש מתנתק מהאפליקציה, צריך להפעיל את השיטה signOut() של לקוח One Tap.
התקשרות אל signOut() משביתה את הכניסה האוטומטית עד שהמשתמש נכנס שוב.
גם אם אתם לא משתמשים בכניסה אוטומטית, השלב הזה חשוב כי הוא מבטיח שכאשר משתמשים יתנתקו מהאפליקציה שלכם, מצב האימות של כל ממשקי ה-API של Play Services שבהם אתם משתמשים יאופס גם כן.
השלבים הבאים
אם הגדרתם את לקוח One Tap לאחזור פרטי כניסה ל-Google, האפליקציה שלכם יכולה עכשיו לקבל אסימוני מזהה של Google שמייצגים את חשבונות Google של המשתמשים. כאן מוסבר איך משתמשים בטוקנים האלה בבק-אנד.
אם אתם תומכים בכניסה באמצעות חשבון Google, אתם יכולים גם להשתמש בלקוח One Tap כדי להוסיף לאפליקציה תהליכי יצירת חשבון חלקים.