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à họ đã dùng trước đó để đăng nhập vào ứng dụng của bạn. Những thông tin đăng nhập này có thể là Tài khoản Google hoặc tổ hợp tên người dùng và mật khẩu mà họ đã lưu bằng Google thông qua tính năng tự động điền của Chrome, Android hoặc Smart Lock cho Mật khẩu.
Khi truy xuất thông tin đăng nhập thành công, bạn có thể sử dụng thông tin đó để đăng nhập người dùng vào ứng dụng của mình một cách dễ dàng.
Nếu người dùng chưa lưu thông tin đăng nhập nào, thì sẽ không có giao diện người dùng nào xuất hiện và bạn có thể cung cấp trải nghiệm thông thường khi người dùng đăng xuất.
Tôi nên sử 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 Đăng nhập bằng một lần nhấn trên màn hình đăng nhập. Điều này có thể hữu ích ngay cả khi bạn đã có nút "Đăng nhập bằng Google": vì bạn có thể định cấu hình giao diện người dùng Một lần nhấn để chỉ hiển thị thông tin đăng nhập mà người dùng đã dùng để đăng nhập trước đó, nên giao diện này có thể nhắc nhở những người dùng ít đăng nhập về cách họ đã đăng nhập lần gần đây nhất và ngăn họ vô tình 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 mọi màn hình có trải nghiệm được nâng cao nhờ đăng nhập. Ví dụ: nếu người dùng có thể duyệt xem nội dung bằng ứng dụng của bạn khi đã đăng xuất, nhưng chỉ có thể đăng bình luận hoặc thêm mặt hàng vào giỏ hàng sau khi đăng nhập, thì đó sẽ là một bối cảnh hợp lý cho tính năng Đă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 nên 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 vì những lý do nêu trên.
Trước khi bắt đầu
- Thiết lập dự án Google API Console và dự án Android như mô tả trong phần Bắt đầu sử dụng tính năng đăng nhập bằng một lần chạm.
- Nếu bạn hỗ trợ tính năng đăng nhập dựa trên mật khẩu, hãy tối ưu hoá ứng dụng của bạn cho tính năng tự động điền (hoặc sử dụng Smart Lock cho Mật khẩu) để người dùng có thể lưu thông tin đăng nhập bằng mật khẩu sau khi đăng nhập.
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 mật khẩu đã lưu, Tài khoản Google đã lưu hoặc cả hai. (Bạn nên hỗ trợ cả hai để cho phép người dùng mới tạo tài khoản bằng một lần nhấn và người dùng cũ đăng nhập tự động hoặc bằng một lần nhấn nhiều nhất có thể.)
Nếu ứng dụng của bạn sử dụng tính năng đăng nhập dựa trên mật khẩu, hãy dùng setPasswordRequestOptions() để bật các yêu cầu về thông tin xác thực bằng 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 về mã nhận dạng Google:
Đặt mã ứng dụng khách máy chủ thành mã nhận dạng mà bạn đã tạo trong bảng điều khiển API của Google. Xin lưu ý rằng đây là mã ứng dụng khách của máy chủ, chứ không phải mã ứng dụng khách Android.
Định cấu hình ứng dụng để lọc theo các tài khoản được uỷ quyền. Khi bạn bật lựa chọn này, ứng dụng Một lần nhấn sẽ 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 mà họ đã dùng trước đây. Việc này có thể giúp người dùng đăng nhập 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 họ đã sử dụng Tài khoản Google nào, đồng thời ngăn người dùng vô tình tạo tài khoản mới bằng ứ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 có
setAutoSelectEnabled(). Người dùng có thể tự động được đăng nhập khi đáp ứng các tiêu chí sau đây:- 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 một số chỉ dùng một lần để cải thiện tính 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 để đưa số chỉ dùng một lần vào mỗi yêu cầu. Hãy xem phần Lấy số chỉ dùng một lần của SafetyNet để biết các đề xuất và thông tin chi tiết khác 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 người dùng đã đăng nhập hay chưa
Nếu Hoạt động của bạn có thể được người dùng đã đăng nhập hoặc người dùng đã đăng xuất sử dụng, 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 tính nă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 hay chưa. Điều này có thể đơn giản như một thuộc tính boolean của Hoạt động. (Xem phần Ngừng hiển thị giao diện người dùng Một lần nhấn bên dưới.)
3. Hiển thị 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 đă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, hãy gọi phương thức beginSignIn() của đối tượng ứng dụng và đính kèm các trình nghe vào Task mà phương thức này trả về. 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 một Hoạt động.
Ứng dụng Một lần nhấn sẽ gọi trình nghe thành công nếu người dùng có thông tin đăng nhập đã lưu cho ứng dụng của bạn. Trong trình nghe thành công, hãy lấy ý định đang chờ xử lý từ kết quả Task và truyền ý định đó đến 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 không có thông tin đăng nhập đã lưu nào, thì ứng dụng Một lần nhấn sẽ gọi 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 trình bày trải nghiệm khi người dùng đăng xuất khỏi ứng dụng. Tuy nhiên, nếu hỗ trợ tính năng đăng ký bằng một lần nhấn, bạn có thể bắt đầu quy trình đó tại đây để có trải nghiệm tạo tài khoản liền mạch. Xem phần 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 đối 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 giao diện người dùng Một lần nhấn hoặc nhấn vào bên ngoài giao diện người dùng này, thì kết quả sẽ trả về mã RESULT_CANCELED. Ứng dụng của bạn cần xử lý cả hai trường hợp này.
Đă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, thì 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() đến phương thức getSignInCredentialFromIntent() của ứng dụng Một lần nhấn. Thông tin đăng nhập sẽ có thuộc tính googleIdToken khác rỗng 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 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 bạn truy xuất được một cặp tên người dùng và mật khẩu, hãy dùng cặp này để đăng nhập theo cách tương tự như khi người dùng cung cấp cặp này theo cách thủ công.
Nếu thông tin đăng nhập Tài khoản Google được truy xuất, hãy dùng mã nhận dạng để xác thực bằng phần phụ trợ của bạn. Nếu bạn đã chọn sử dụng một số chỉ dùng một lần để tránh các cuộc tấn công phát lại, hãy kiểm tra giá trị phản hồi trên máy chủ phụ trợ. Xem phần Xác thực bằng một phần phụ trợ bằng cách sử dụng 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) { // ... } } } } // ... }
Ngừng hiển thị giao diện người dùng Một lần nhấn
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 Đăng nhập bằng một lần chạm để 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 thực hiện việc này bằng cách đặt một thuộc tính trên Hoạt động mà ứng dụng dùng để xác định xem có nên cung cấp tính năng Đăng nhập bằng một lần chạm cho người dùng hay không; tuy nhiên, bạn cũng có thể lưu một giá trị vào SharedPreferences hoặc sử dụng một phương thức khác.
Điều quan trọng là bạn phải triển khai tính năng giới hạn tốc độ của riêng mình 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ỷ nhiều lời nhắc liên tiếp, thì ứng dụng Một lần nhấn sẽ không nhắc người dùng trong 24 giờ tiếp theo.
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ý khi đă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 nhấn.
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 rất quan trọng vì nó đảm bảo rằng khi người dùng đăng xuất khỏi ứng dụng của bạn, trạng thái xác thực của mọi API 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 nhấn để truy xuất thông tin đăng nhập Google, thì ứng dụng của bạn hiện có thể nhận được mã thông báo nhận dạng Google đại diện cho Tài khoản Google của người dùng. Tìm hiểu cách bạn có thể sử dụng các mã thông báo này trên phần phụ trợ.
Nếu hỗ trợ tính năng Đăng nhập bằng Google, bạn cũng có thể dùng ứng dụng Một lần nhấn để thêm quy trình tạo tài khoản liền mạch vào ứng dụng của mình.