Đăng nhập cho người dùng bằng thông tin xác thực mà họ đã lưu

Sử dụng ứng dụng đăng nhập bằng một lần chạm để yêu cầu người dùng cấp quyền truy xuất một trong những thông tin đăng nhập mà trước đây họ đã sử dụng để đăng nhập vào ứng dụng của bạn. Các thông tin đăng nhập có thể là một Tài khoản Google hoặc tổ hợp tên người dùng và mật khẩu con đã lưu trên Google bằng cách sử dụng Chrome, tính năng tự động điền của Android hoặc Smart Lock cho Mật khẩu.

Giao diện người dùng đăng nhập bằng một lần nhấn

Khi thông tin xác thực được truy xuất thành công, bạn có thể sử dụng thông tin đó để dễ dàng đăng nhập người dùng vào ứng dụng của bạn.

Nếu người dùng chưa lưu bất kỳ thông tin đăng nhập nào thì sẽ không có giao diện người dùng nào hiển thị và bạn có thể mang lại trải nghiệm đăng xuất thông thường.

Tôi nên dùng tính năng Đăng nhập bằng một lần chạm ở đâu?

Nếu ứng dụng của bạn yêu cầu người dùng đăng nhập, hãy hiển thị giao diện người dùng Một lần chạm khi bạn đăng nhập màn hình. Tính năng này có thể hữu ích ngay cả khi bạn đã có tính năng "Đăng nhập bằng Google" vì giao diện người dùng Một lần chạm có thể được định cấu hình để chỉ hiển thị thông tin đăng nhập người dùng từng sử dụng để đăng nhập, đây có thể là lời nhắc cho những người dùng không thường xuyên đăng nhập cách trẻ đăng nhập lần gần đây nhất và ngăn trẻ vô tình đăng nhập tạo tài khoản mới bằng ứng dụng của bạn.

Nếu ứng dụng của bạn không bắt buộc phải đăng nhập, hãy cân nhắc sử dụng tính năng Đăng nhập bằng một lần chạm trên bất kỳ màn hình có trải nghiệm được cải thiện bằng cách đăng nhập. Ví dụ: nếu người dùng có thể duyệt nội dung bằng ứng dụng của bạn khi đã đăng xuất, nhưng chỉ có thể đăng nhận xét hoặc thêm mặt hàng vào giỏ hàng sau khi đăng nhập. Đó sẽ là ngữ cảnh hợp lý cho Đăng nhập bằng một lần chạm.

Các ứng dụng không bắt buộc đăng nhập cũng phải sử dụng tính năng Đăng nhập bằng một lần chạm trên màn hình đăng nhập của các ứng dụng đó, vì những lý do nêu trên.

Trước khi bắt đầu

1. Định cấu hình ứng dụng đăng nhập bằng một lần chạm

Bạn có thể định cấu hình ứng dụng đăng nhập bằng một lần chạm để đăng nhập cho người dùng bằng các mục đã lưu mật khẩu, Tài khoản Google đã lưu hoặc một trong hai tính năng đó. (Bạn nên hỗ trợ cả hai, để bật tính năng tạo tài khoản bằng một lần nhấn cho người dùng mới và bật tính năng tự động hoặc đăng nhập bằng một lần nhấn cho càng nhiều người dùng cũ càng tốt).

Nếu ứng dụng của bạn sử dụng phương thức đăng nhập dựa trên mật khẩu, hãy dùng setPasswordRequestOptions() để bật yêu cầu thông tin xác thực mật khẩu.

Nếu ứng dụng của bạn sử dụng tính năng Đăng nhập bằng Google, hãy dùng setGoogleIdTokenRequestOptions() để bật và định cấu hình các yêu cầu mã thông báo giá trị nhận dạng của Google:

  • Đặt mã ứng dụng khách của máy chủ thành mã mà bạn đã tạo trong các API của Google Google Play Console. Lưu ý rằng đây là ID ứng dụng khách của máy chủ của bạn, không phải mã ứng dụng khách Android của bạn.

  • Định cấu hình ứng dụng để lọc theo tài khoản được uỷ quyền. Khi bạn bật tính năng này thì ứng dụng Một lần chạm chỉ nhắc người dùng đăng nhập vào ứng dụng của bạn bằng Tài khoản Google họ đã sử dụng trong quá khứ. Việc này có thể giúp người dùng ký thành công khi họ không chắc chắn liệu họ đã có tài khoản hay chưa hoặc Tài khoản Google họ đã sử dụng và ngăn người dùng vô tình tạo tài khoản mới tài khoản với ứng dụng của bạn.

  • Nếu bạn muốn tự động đăng nhập người dùng khi có thể, hãy bật tính năng này cùng với setAutoSelectEnabled(). Có thể tự động đăng nhập khi các tiêu chí sau:

    • Người dùng đã lưu chính xác một thông tin đăng nhập cho ứng dụng của bạn. Tức là người dùng đã lưu một mật khẩu hoặc một Tài khoản Google.
    • Người dùng chưa tắt tính năng tự động đăng nhập trong phần Cài đặt Tài khoản Google.
  • Mặc dù không bắt buộc nhưng bạn nên cân nhắc sử dụng số chỉ dùng một lần để cải thiện khả năng bảo mật khi đăng nhập và tránh các cuộc tấn công phát lại. Sử dụng setNonce để thêm một số chỉ dùng một lần vào mỗi yêu cầu. Xem SafetyNet Lấy một số chỉ dùng một lần để biết các đề xuất và thông tin chi tiết bổ sung về cách tạo số chỉ dùng một lần.

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. Kiểm tra xem có người dùng đã đăng nhập không

Nếu người dùng đã đăng nhập hoặc người dùng đã đăng xuất có thể sử dụng Hoạt động của bạn, hãy kiểm tra trạng thái của người dùng trước khi hiển thị giao diện người dùng đăng nhập bằng một lần chạm.

Bạn cũng nên theo dõi xem người dùng đã từ chối sử dụng Đăng nhập bằng một lần chạm bằng cách đóng lời nhắc hoặc nhấn vào bên ngoài lời nhắc. Điều này có thể đơn giản như một thuộc tính boolean của Hoạt động. (Xem mục Ngừng hiển thị giao diện người dùng Một lần chạm ở bên dưới.)

3. Hiển thị giao diện người dùng cho tính năng đăng nhập bằng một lần chạm

Nếu người dùng chưa đăng nhập và chưa từ chối sử dụng tính năng đăng nhập bằng một lần chạm, gọi phương thức beginSignIn() của đối tượng ứng dụng và đính kèm trình nghe vào Trả về Task. Các ứng dụng thường thực hiện việc này trong phương thức onCreate() của Hoạt động hoặc sau khi chuyển đổi màn hình khi sử dụng cấu trúc Hoạt động đơn.

Ứng dụng Một lần chạm sẽ gọi trình nghe thành công nếu người dùng có thông tin xác thực cho ứng dụng của mình. Trong trình nghe thành công, hãy lấy ý định đang chờ xử lý từ kết quả Task rồi chuyển kết quả đó vào startIntentSenderForResult() để bắt đầu Giao diện người dùng đăng nhập bằng một lần chạm.

Nếu người dùng chưa lưu bất kỳ thông tin đăng nhập nào, thì ứng dụng Một lần chạm sẽ gọi hàm trình nghe lỗi. Trong trường hợp này, bạn không cần làm gì cả: bạn chỉ cần tiếp tục thể hiện trải nghiệm khi đã đăng xuất trong ứng dụng. Tuy nhiên, nếu bạn hỗ trợ tính năng Một lần chạm bạn có thể bắt đầu quy trình đó tại đây để tạo tài khoản liền mạch của bạn. Hãy xem bài viết Tạo tài khoản mới chỉ bằng một lần nhấn.

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. Xử lý phản hồi của người dùng

Phản hồi của người dùng với lời nhắc đăng nhập bằng một lần chạm sẽ được báo cáo cho ứng dụng của bạn bằng phương thức onActivityResult() của Hoạt động. Nếu người dùng chọn đăng nhập, kết quả sẽ là thông tin đăng nhập đã lưu. Nếu người dùng từ chối đăng nhập, bằng cách đóng hoặc nhấn vào bên ngoài giao diện người dùng, kết quả sẽ trả về cùng với mã RESULT_CANCELED. Ứng dụng của bạn cần xử lý được cả hai khả năng.

Đăng nhập bằng thông tin đăng nhập đã truy xuất

Nếu người dùng chọn chia sẻ thông tin đăng nhập với ứng dụng của bạn, bạn có thể truy xuất thông tin đăng nhập đó bằng cách truyền dữ liệu ý định từ onActivityResult() sang ứng dụng Một lần chạm getSignInCredentialFromIntent(). Thông tin đăng nhập sẽ không có giá trị rỗng googleIdToken nếu người dùng đã chia sẻ thông tin đăng nhập Tài khoản Google với ứng dụng của bạn hoặc một thuộc tính password khác rỗng nếu người dùng chia sẻ mật khẩu đã lưu.

Sử dụng thông tin đăng nhập để xác thực với phần phụ trợ của ứng dụng.

  • Nếu một cặp tên người dùng và mật khẩu được truy xuất, hãy sử dụng chúng để đăng nhập vào cùng một tài khoản theo cách bạn sẽ làm nếu người dùng cung cấp chúng theo cách thủ công.
  • Nếu thông tin đăng nhập của Tài khoản Google được truy xuất, hãy sử dụng mã thông báo nhận dạng để xác thực với phần phụ trợ của bạn. Nếu bạn đã chọn sử dụng số chỉ dùng một lần để tránh phát lại tấn công kiểm tra giá trị phản hồi trên máy chủ phụ trợ của bạn. Xem Xác thực bằng phần phụ trợ bằng mã thông báo mã nhận dạng.

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

Dừng hiển thị giao diện người dùng Một lần chạm

Nếu người dùng từ chối đăng nhập, lệnh gọi đến getSignInCredentialFromIntent() sẽ gửi một ApiException có mã trạng thái CommonStatusCodes.CANCELED. Khi điều này xảy ra, bạn nên tạm thời tắt giao diện người dùng của tính năng đăng nhập bằng một lần chạm để bạn không làm phiền người dùng bằng các lời nhắc lặp lại. Ví dụ sau đây hoàn thành điều này bằng cách đặt thuộc tính trên Hoạt động. Thuộc tính này sử dụng thuộc tính này để xác định xem để cung cấp cho người dùng tính năng đăng nhập bằng một lần chạm; tuy nhiên, bạn cũng có thể lưu giá trị để SharedPreferences hoặc sử dụng phương thức khác.

Bạn cần phải triển khai giới hạn số lượng yêu cầu của riêng bạn cho lời nhắc đăng nhập bằng một lần chạm. Nếu bạn không làm như vậy và người dùng huỷ một số lời nhắc trong một hàng, thì ứng dụng Một lần chạm sẽ không nhắc người dùng trong 24 giờ tới.

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. Xử lý quá trình đăng xuất

Khi người dùng đăng xuất khỏi ứng dụng, hãy gọi phương thức signOut() của ứng dụng Một lần chạm. Việc gọi signOut() sẽ tắt tính năng tự động đăng nhập cho đến khi người dùng đăng nhập lại.

Ngay cả khi bạn không sử dụng tính năng tự động đăng nhập, bước này vẫn quan trọng vì đảm bảo rằng khi người dùng đăng xuất khỏi ứng dụng, trạng thái xác thực của bất kỳ Các API của Dịch vụ Play mà bạn sử dụng cũng sẽ được đặt lại.

Các bước tiếp theo

Nếu bạn đã định cấu hình ứng dụng Một lần chạm để truy xuất thông tin đăng nhập Google, thì ứng dụng của bạn hiện có thể nhận mã thông báo ID Google đại diện cho người dùng của bạn Tài khoản Google. Học hỏi cách sử dụng các mã thông báo này trong phần phụ trợ.

Nếu bạn hỗ trợ tính năng Đăng nhập bằng Google, bạn cũng có thể sử dụng ứng dụng Một lần chạm để thêm tạo tài khoản suôn sẻ cho ứng dụng của bạn.