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

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

ממשק המשתמש של כניסה בלחיצה אחת

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

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

איפה כדאי להשתמש בכניסה בלחיצה אחת?

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

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

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

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

1. הגדרת לקוח הכניסה בהקשה אחת

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

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

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

  • מגדירים את מזהה הלקוח של השרת למזהה שיצרתם במסוף Google APIs. חשוב לזכור שזהו מזהה הלקוח של השרת, ולא מזהה הלקוח של Android.

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

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

    • למשתמש יש רק פרטי כניסה אחד שמורים לאפליקציה. כלומר, סיסמה אחת שמורה או חשבון Google אחד שמורה.
    • המשתמש לא השבית את הכניסה האוטומטית בהגדרות של חשבון Google.
  • השימוש ב-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. בדיקה אם משתמש מחובר לחשבון

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

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

3. הצגת ממשק המשתמש של הכניסה בלחיצה אחת

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

לקוח One Tap יבצע קריאה למאזין לאירועי הצלחה אם למשתמש יש פרטי כניסה שמורים לאפליקציה. במאזין לאירועי הצלחה, מקבלים את ה-intent בהמתנה מהתוצאה Task ומעבירים אותו אל startIntentSenderForResult() כדי להפעיל את ממשק המשתמש של הכניסה ב-One Tap.

אם למשתמש אין פרטי כניסה שמורים, הלקוח של 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() של הפעילות. אם המשתמש בחר להיכנס, התוצאה תהיה פרטי כניסה שמורים. אם המשתמש דחה את הכניסה, בין שבאמצעות סגירת ממשק המשתמש של One Tap ובין שבאמצעות הקשה מחוץ לממשק, התוצאה תוחזר עם הקוד RESULT_CANCELED. האפליקציה צריכה לטפל בשתי האפשרויות.

כניסה באמצעות פרטי הכניסה שאוחזרו

אם המשתמש בחר לשתף את פרטי הכניסה עם האפליקציה, תוכלו לאחזר אותם על ידי העברת נתוני הכוונה מ-onActivityResult() לשיטה getSignInCredentialFromIntent() של לקוח One Tap. אם המשתמש שיתף עם האפליקציה פרטי כניסה לחשבון Google, למאפיין googleIdToken יהיה ערך שונה מאפס. אם המשתמש שיתף סיסמה שמורה, למאפיין password יהיה ערך שונה מאפס.

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

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

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) {
                    // ...
                }
            }
        }
    }
    // ...
}

הפסקת הצגת ממשק המשתמש של One Tap

אם המשתמש דחה את הכניסה, הקריאה ל-getSignInCredentialFromIntent() תגרום להשלכת ApiException עם קוד סטטוס CommonStatusCodes.CANCELED. במקרה כזה, מומלץ להשבית באופן זמני את ממשק המשתמש של כניסה בנגיעה אחת כדי לא להטריד את המשתמשים בהנחיות חוזרות. בדוגמה הבאה, המערכת קובעת אם להציע למשתמש כניסה בנגיעה אחת על ידי הגדרת מאפיין בפעילות. עם זאת, אפשר גם לשמור ערך ב-SharedPreferences או להשתמש בשיטה אחרת.

חשוב להטמיע הגבלת קצב משלכם להצגת הנחיות לכניסה בהקשה אחת. אם לא תעשו זאת, ומשתמש יבטל כמה הנחיות ברציפות, לקוח One Tap לא יציג למשתמש הנחיות במשך 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 כדי להוסיף לאפליקציה תהליכי יצירה של חשבון ללא פשרות.