کاربران را با اطلاعات کاربری ذخیره شده خود وارد سیستم کنید

از سرویس ورود با یک لمس (One Tap sign-in client) برای درخواست مجوز از کاربر جهت بازیابی یکی از اطلاعات کاربری که قبلاً برای ورود به برنامه شما استفاده کرده است، استفاده کنید. این اطلاعات کاربری می‌تواند یک حساب گوگل یا ترکیبی از نام کاربری و رمز عبوری باشد که کاربر با استفاده از کروم، تکمیل خودکار فرم اندروید یا قفل هوشمند برای رمزهای عبور، در گوگل ذخیره کرده است.

رابط کاربری ورود با یک لمس

وقتی اعتبارنامه‌ها با موفقیت بازیابی شدند، می‌توانید از آنها برای ورود آسان کاربر به برنامه خود استفاده کنید.

اگر کاربر هیچ اطلاعات کاربری ذخیره نکرده باشد، هیچ رابط کاربری نمایش داده نمی‌شود و شما می‌توانید تجربه عادی خروج از سیستم خود را ارائه دهید.

کجا باید از ورود با یک لمس استفاده کنم؟

اگر برنامه شما نیاز به ورود کاربران دارد، رابط کاربری One Tap را در صفحه ورود به سیستم نمایش دهید. این می‌تواند مفید باشد حتی اگر از قبل دکمه "ورود با گوگل" را داشته باشید: از آنجا که رابط کاربری One Tap را می‌توان طوری پیکربندی کرد که فقط اعتبارنامه‌هایی را که کاربر قبلاً برای ورود به سیستم استفاده کرده است نشان دهد، می‌تواند یادآوری برای کاربرانی باشد که به ندرت وارد سیستم می‌شوند و نحوه ورود قبلی خود را به خاطر می‌سپارند و از ایجاد تصادفی حساب‌های جدید در برنامه شما جلوگیری می‌کند.

اگر ورود به سیستم برای برنامه شما اختیاری است، استفاده از ورود با یک ضربه را در هر صفحه‌ای که با ورود به سیستم تجربه بهتری دارد، در نظر بگیرید. برای مثال، اگر کاربران بتوانند در هنگام خروج از سیستم، محتوا را با برنامه شما مرور کنند، اما فقط پس از ورود به سیستم می‌توانند نظر ارسال کنند یا اقلامی را به سبد خرید اضافه کنند، این یک زمینه معقول برای ورود با یک ضربه خواهد بود.

برنامه‌های اختیاری ورود به سیستم نیز باید به دلایلی که در بالا ذکر شد، از ورود با یک ضربه (One Tap) در صفحه‌های ورود به سیستم خود استفاده کنند.

قبل از اینکه شروع کنی

  • پروژه کنسول Google APIs و پروژه اندروید خود را همانطور که در «شروع با ورود با یک ضربه» توضیح داده شده است، تنظیم کنید.
  • اگر از ورود به سیستم مبتنی بر رمز عبور پشتیبانی می‌کنید، برنامه خود را برای تکمیل خودکار بهینه کنید (یا از قفل هوشمند برای رمزهای عبور استفاده کنید) تا کاربران بتوانند پس از ورود به سیستم، اعتبارنامه رمز عبور خود را ذخیره کنند.

۱. کلاینت ورود با یک لمس را پیکربندی کنید

شما می‌توانید کلاینت ورود با یک لمس را طوری پیکربندی کنید که کاربران را با رمزهای عبور ذخیره‌شده، حساب‌های گوگل ذخیره‌شده یا هر دو وارد سیستم کند. (پشتیبانی از هر دو توصیه می‌شود تا ایجاد حساب کاربری با یک لمس برای کاربران جدید و ورود خودکار یا با یک لمس برای حداکثر تعداد ممکن از کاربران قدیمی امکان‌پذیر باشد.)

اگر برنامه شما از ورود مبتنی بر رمز عبور استفاده می‌کند، از setPasswordRequestOptions() برای فعال کردن درخواست‌های اعتبارنامه با رمز عبور استفاده کنید.

اگر برنامه شما از ورود به سیستم گوگل استفاده می‌کند، از setGoogleIdTokenRequestOptions() برای فعال کردن و پیکربندی درخواست‌های توکن شناسه گوگل استفاده کنید:

  • شناسه کلاینت سرور را روی شناسه‌ای که در کنسول APIهای گوگل ایجاد کرده‌اید، تنظیم کنید. توجه داشته باشید که این شناسه کلاینت سرور شماست، نه شناسه کلاینت اندروید شما.

  • کلاینت را طوری پیکربندی کنید که بر اساس حساب‌های کاربری مجاز فیلتر شود. وقتی این گزینه را فعال می‌کنید، کلاینت One Tap فقط از کاربران می‌خواهد که با حساب‌های کاربری گوگلی که قبلاً استفاده کرده‌اند، وارد برنامه شما شوند. انجام این کار می‌تواند به کاربران کمک کند تا وقتی مطمئن نیستند که آیا قبلاً حسابی دارند یا از کدام حساب کاربری گوگل استفاده کرده‌اند، با موفقیت وارد سیستم شوند و از ایجاد تصادفی حساب‌های کاربری جدید توسط کاربران در برنامه شما جلوگیری می‌کند.

  • اگر می‌خواهید کاربران در صورت امکان به صورت خودکار وارد سیستم شوند، این ویژگی را با setAutoSelectEnabled() فعال کنید. ورود خودکار زمانی امکان‌پذیر است که معیارهای زیر رعایت شوند:

    • کاربر دقیقاً یک اعتبارنامه برای برنامه شما ذخیره کرده است. یعنی یک رمز عبور ذخیره شده یا یک حساب گوگل ذخیره شده.
    • کاربر ورود خودکار را در تنظیمات حساب گوگل خود غیرفعال نکرده است.
  • اگرچه اختیاری است، توصیه می‌کنیم برای بهبود امنیت ورود به سیستم و جلوگیری از حملات تکرار، استفاده از nonce را به شدت در نظر بگیرید. از setNonce برای گنجاندن nonce در هر درخواست استفاده کنید. برای پیشنهادات و جزئیات بیشتر در مورد ایجاد nonce، به بخش Obtain a nonce در SafetyNet مراجعه کنید.

جاوا

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

کاتلین

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

۲. بررسی کنید که آیا کاربر وارد سیستم شده است یا خیر

اگر فعالیت شما می‌تواند توسط یک کاربر وارد شده یا یک کاربر خارج شده استفاده شود، قبل از نمایش رابط کاربری ورود با یک ضربه، وضعیت کاربر را بررسی کنید.

همچنین باید پیگیری کنید که آیا کاربر قبلاً با بستن اعلان یا ضربه زدن به خارج از آن، از استفاده از ورود با One Tap خودداری کرده است یا خیر. این می‌تواند به سادگی یک ویژگی بولی از Activity شما باشد. (به بخش «توقف نمایش رابط کاربری One Tap» در زیر مراجعه کنید.)

۳. رابط کاربری ورود با یک لمس را نمایش دهید

اگر کاربر وارد سیستم نشده و هنوز استفاده از ورود با یک لمس را رد نکرده است، متد beginSignIn() شیء کلاینت را فراخوانی کنید و شنونده‌ها را به Task که برمی‌گرداند، متصل کنید. برنامه‌ها معمولاً این کار را در متد onCreate() مربوط به Activity یا پس از انتقال صفحه هنگام استفاده از معماری تک‌فعالیتی انجام می‌دهند.

اگر کاربر هرگونه اطلاعات ورود ذخیره شده‌ای برای برنامه شما داشته باشد، کلاینت One Tap، شنونده موفقیت (success listener) را فراخوانی می‌کند. در شنونده موفقیت، intent در حال انتظار را از نتیجه Task دریافت کرده و آن را به startIntentSenderForResult() ارسال کنید تا رابط کاربری ورود به سیستم One Tap آغاز شود.

اگر کاربر هیچ اعتبارنامه ذخیره‌شده‌ای نداشته باشد، کلاینت One Tap شنونده‌ی خطا را فراخوانی می‌کند. در این حالت، هیچ اقدامی لازم نیست: می‌توانید به سادگی به ارائه‌ی تجربه‌ی خروج از سیستم برنامه ادامه دهید. با این حال، اگر از ثبت‌نام One Tap پشتیبانی می‌کنید، می‌توانید این جریان را برای یک تجربه‌ی ایجاد حساب کاربری یکپارچه از اینجا شروع کنید. به بخش «ایجاد حساب‌های جدید با یک لمس» مراجعه کنید.

جاوا

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());
            }
        });

کاتلین

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)
    }

۴. پاسخ کاربر را مدیریت کنید

پاسخ کاربر به درخواست ورود با One Tap با استفاده از متد onActivityResult() در Activity به برنامه شما گزارش می‌شود. اگر کاربر ورود به سیستم را انتخاب کرده باشد، نتیجه یک اعتبارنامه ذخیره شده خواهد بود. اگر کاربر از ورود به سیستم، چه با بستن رابط کاربری One Tap و چه با ضربه زدن به خارج از آن، خودداری کند، نتیجه با کد RESULT_CANCELED بازگردانده می‌شود. برنامه شما باید هر دو احتمال را مدیریت کند.

با اعتبارنامه‌های بازیابی‌شده وارد شوید

اگر کاربر تصمیم گرفته باشد که اطلاعات احراز هویت (credentials) را با برنامه شما به اشتراک بگذارد، می‌توانید با ارسال داده‌های intent از onActivityResult() به متد getSignInCredentialFromIntent() در کلاینت One Tap، آنها را بازیابی کنید. اگر کاربر اطلاعات احراز هویت حساب گوگل (Google Account) خود را با برنامه شما به اشتراک گذاشته باشد، اطلاعات احراز هویت دارای یک ویژگی googleIdToken غیر تهی (non-null) خواهد بود، یا اگر کاربر رمز عبور ذخیره شده (save password) خود را به اشتراک گذاشته باشد، دارای یک ویژگی password غیر تهی (non-null) خواهد بود.

از اعتبارنامه برای تأیید اعتبار با backend برنامه خود استفاده کنید.

  • اگر یک جفت نام کاربری و رمز عبور بازیابی شد، از آنها برای ورود به سیستم به همان روشی که اگر کاربر آنها را به صورت دستی وارد کرده بود، استفاده می‌کردید، استفاده کنید.
  • اگر اطلاعات حساب گوگل شما بازیابی شده باشد، از توکن شناسه برای احراز هویت با سرور بک‌اند خود استفاده کنید. اگر برای جلوگیری از حملات تکرارشونده، استفاده از nonce را انتخاب کرده‌اید، مقدار پاسخ را در سرور بک‌اند خود بررسی کنید. به بخش احراز هویت با بک‌اند با استفاده از توکن‌های شناسه مراجعه کنید.

جاوا

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;
      }
  }
}

کاتلین

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 ایجاد می‌کند. در این صورت، باید رابط کاربری ورود با یک ضربه (One Tap) را موقتاً غیرفعال کنید تا کاربران خود را با درخواست‌های مکرر آزار ندهید. مثال زیر این کار را با تنظیم یک ویژگی در Activity انجام می‌دهد که از آن برای تعیین اینکه آیا ورود با یک ضربه را به کاربر ارائه دهد یا خیر، استفاده می‌کند. با این حال، می‌توانید مقداری را در SharedPreferences ذخیره کنید یا از روش دیگری استفاده کنید.

مهم است که محدودیت سرعت خود را برای اعلان‌های ورود با One Tap پیاده‌سازی کنید. اگر این کار را نکنید و کاربر چندین اعلان را پشت سر هم لغو کند، کلاینت One Tap تا ۲۴ ساعت آینده اعلانی به کاربر ارسال نخواهد کرد.

جاوا

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;
      }
  }
}

کاتلین

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

۵. خروج از سیستم را مدیریت کنید

وقتی کاربر از برنامه شما خارج می‌شود، متد signOut() از کلاینت One Tap را فراخوانی کنید. فراخوانی signOut() ورود خودکار را تا زمانی که کاربر دوباره وارد شود غیرفعال می‌کند.

حتی اگر از ورود خودکار استفاده نمی‌کنید، این مرحله مهم است زیرا تضمین می‌کند که وقتی کاربران از برنامه شما خارج می‌شوند، وضعیت احراز هویت هر API سرویس‌های Play که استفاده می‌کنید نیز بازنشانی می‌شود.

مراحل بعدی

اگر کلاینت One Tap را برای بازیابی اطلاعات احراز هویت گوگل پیکربندی کرده باشید، برنامه شما اکنون می‌تواند توکن‌های شناسه گوگل را که نشان‌دهنده حساب‌های گوگل کاربران شما هستند، دریافت کند. بیاموزید که چگونه می‌توانید از این توکن‌ها در backend استفاده کنید .

اگر از ورود به سیستم با گوگل پشتیبانی می‌کنید، می‌توانید از کلاینت One Tap نیز برای افزودن جریان‌های ایجاد حساب کاربری بدون مشکل به برنامه خود استفاده کنید.