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

از کارخواه ورود به سیستم «با یک ضربه» استفاده کنید تا از کاربر اجازه بگیرید یکی از اعتبارنامه‌هایی را که قبلاً برای ورود به سیستم برنامه‌تان استفاده کرده است بازیابی کنید. این اعتبارنامه‌ها می‌توانند «حساب Google» یا ترکیب نام کاربری و گذرواژه‌ای باشند که کاربر بااستفاده از Chrome، تکمیل خودکار Android، یا Smart Lock برای گذرواژه‌ها در Google ذخیره کرده است.

واسط کاربر ورود به سیستم با یک تک‌ضرب

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

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

کجا باید از ورود به سیستم با «تک‌ضرب» استفاده کنم؟

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

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

برنامه‌هایی که ورود به سیستم در آن‌ها اختیاری است نیز باید به همان دلایل از «ورود به سیستم با تک‌ضرب» در صفحه‌های ورود به سیستم خود استفاده کنند.

قبل‌از شروع

۱. پیکربندی کردن کارخواه ورود به سیستم با «تک‌ضرب»

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

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

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

  • شناسه کارخواه سرور را روی شناسه‌ای که در کنسول Google Cloud ایجاد کردید تنظیم کنید. توجه داشته باشید که این شناسه کارخواه سرور شما است، نه شناسه کارخواه Android شما.

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

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

    • کاربر دقیقاً یک اعتبارنامه ذخیره‌شده برای برنامه شما دارد. یعنی یک گذرواژه ذخیره‌شده یا یک «حساب Google» ذخیره‌شده.
    • کاربر ورود خودکار به سیستم را در تنظیمات «حساب Google» خود غیرفعال نکرده باشد.
  • هرچند اختیاری است، اکیداً توصیه می‌کنیم برای بهبود امنیت ورود به سیستم و جلوگیری از حملات تکراری، از یکبارکد استفاده کنید. از setNonce استفاده کنید تا در هر درخواست یک 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 UI در زیر مراجعه کنید.)

۳. نمایش واسط کاربر ورود به سیستم با «تک‌ضرب»

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

  • اعتبارنامه ذخیره‌شده پیدا شد: اگر کاربر اعتبارنامه ذخیره‌شده‌ای برای برنامه‌تان داشته باشد، کارخواه One Tap شنونده موفقیت را فراخوانی می‌کند. در شنونده موفقیت، قصد معوق را از نتیجه Task دریافت کنید و آن را به startIntentSenderForResult() ارسال کنید تا میانای کاربری ورود به سیستم 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() «فعالیت» شما به برنامه‌تان گزارش خواهد شد. اگر کاربر ورود به سیستم را انتخاب کند، نتیجه یک اعتبارنامه ذخیره‌شده خواهد بود. اگر کاربر از ورود به سیستم خودداری کند، چه با بستن One Tap UI یا ضربه زدن در خارج از آن، نتیجه با کد RESULT_CANCELED برگردانده می‌شود. برنامه شما باید هر دو احتمال را مدیریت کند.

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

اگر کاربر انتخاب کرده باشد که اطلاعات کاربری را با برنامه‌تان هم‌رسانی کند، می‌توانید آن‌ها را با ارسال داده‌های هدف از onActivityResult() به روش getSignInCredentialFromIntent() مشتری One Tap بازیابی کنید. اگر کاربر اعتبارنامه «حساب Google» را با برنامه شما هم‌رسانی کرده باشد، اعتبارنامه دارای ویژگی غیرتهی googleIdToken خواهد بود، و اگر کاربر گذرواژه ذخیره‌شده‌ای را هم‌رسانی کرده باشد، اعتبارنامه دارای ویژگی غیرتهی password خواهد بود.

از اعتبارنامه برای اصالت‌سنجی با پس‌بست برنامه‌تان استفاده کنید.

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

جاوا

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 UI

اگر کاربر ورود به سیستم را رد کند، تماس با getSignInCredentialFromIntent() یک ApiException با کد وضعیت CommonStatusCodes.CANCELED ایجاد خواهد کرد. وقتی این اتفاق می‌افتد، باید موقتاً میانای کاربر ورود به سیستم با «یک ضربه» را غیرفعال کنید تا کاربران را با پیام‌واره‌های مکرر آزار ندهید. مثال زیر این کار را با تنظیم یک ویژگی در «فعالیت» انجام می‌دهد که از آن برای تعیین اینکه آیا ورود به سیستم با «یک تک‌ضرب» به کاربر پیشنهاد شود یا نه استفاده می‌کند؛ بااین‌حال، می‌توانید مقداری را در SharedPreferences ذخیره کنید یا از روش دیگری استفاده کنید.

مهم است که محدودیت نرخ خودتان را برای پیام‌واره‌های ورود به سیستم با «تک‌ضرب» پیاده‌سازی کنید. اگر این کار را نکنید و کاربر چند پیام‌واره را پشت‌سرهم لغو کند، سرویس‌گیرنده 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() ورود خودکار به سیستم را تا زمانی که کاربر دوباره به سیستم وارد شود غیرفعال می‌کند.

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

مراحل بعدی

اگر کارخواه One Tap را برای بازیابی اطلاعات کاربری Google پیکربندی کرده باشید، برنامه‌تان اکنون می‌تواند نشان‌های شناسه Google را که نشان‌دهنده «حساب‌های Google» کاربران شما است دریافت کند. با نحوه استفاده از این توکن‌ها در پس‌زمینه آشنا شوید.

اگر از «ورود به سیستم با Google» پشتیبانی می‌کنید، می‌توانید از سرویس‌گیرنده One Tap نیز برای افزودن جریان‌های ایجاد حساب بدون اصطکاک به برنامه‌تان استفاده کنید.