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 các thông tin xác thực mà họ đã dùng trước đó để đăng nhập vào ứng dụng của bạn. Các thông tin xác thực này có thể là Tài khoản Google hoặc tổ hợp tên người dùng-mật khẩu mà họ đã lưu với Google bằng Chrome, tính năng tự động điền của Android hoặc tính năng Khoá thông minh cho mật khẩu.
Khi truy xuất thành công thông tin xác thực, 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 liền mạch.
Nếu người dùng chưa lưu thông tin xác thực nào, thì giao diện người dùng sẽ không xuất hiện và bạn có thể cung cấp trải nghiệm đăng xuất thông thường.
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 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ì giao diện người dùng One Tap có thể được định cấu hình để chỉ hiển thị thông tin xác thực mà người dùng từng dùng để đăng nhập, nên đây có thể là lời nhắc cho những người dùng không thường xuyên đăng nhập về cách họ đã đăng nhập lần trước 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 khi đăng nhập. Ví dụ: nếu người dùng có thể duyệt qua 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à bối cảnh hợp lý để đăng nhập bằng tính năng Một lần nhấn.
Các ứng dụng không bắt buộc phải đăng nhập cũng nên sử dụng tính năng Đăng nhập một lần chạm trên màn hình đăng nhập của chúng, vì những lý do nêu trên.
Trước khi bắt đầu
- Thiết lập dự án Bảng điều khiển API của Google và dự án Android như mô tả trong phần Bắt đầu sử dụng tính năng Đăng nhập một lần.
- 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 để 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ười dùng đăng nhập bằng mật khẩu đã lưu, Tài khoản Google đã lưu hoặc một trong hai. (Bạn nên hỗ trợ cả hai tính năng để cho phép tạo tài khoản bằng một lần nhấn cho người dùng mới và đăng nhập tự động hoặc bằng một lần nhấn cho nhiều người dùng cũ 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 sử dụng setPasswordRequestOptions()
để bật các yêu cầu 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 sử dụng setGoogleIdTokenRequestOptions()
để bật và định cấu hình các yêu cầu mã thông báo nhận dạng của Google:
Đặt mã ứng dụng khách của máy chủ thành 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 tài khoản được uỷ quyền. Khi bạn bật tuỳ chọn này, ứng dụng One Tap 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ọ đã sử 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 mình đã có tài khoản hay chưa hoặc đã 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 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 Nhận 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 người dùng đã đăng nhập
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 tính năng Một lần nhấn.
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 một lần hay chưa 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 phần Dừ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 một lần, hãy gọi phương thức beginSignIn()
của đối tượng ứng dụng và đính kèm 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 Hoạt động đơn.
Ứng dụng One Tap sẽ gọi trình nghe thành công nếu người dùng có thông tin xác thực đã 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à chuyển ý định đó đến startIntentSenderForResult()
để bắt đầu giao diện người dùng đăng nhập bằng tính năng One Tap.
Nếu người dùng không có thông tin xác thực nào được lưu, thì ứng dụng One Tap 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 đã đăng xuất của ứ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 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 đối với lời nhắc đăng nhập bằng tính năng Một lần nhấn sẽ được báo cáo cho ứng dụng của bạn bằng cách sử dụ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 xác thực đã 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 One Tap hoặc nhấn vào bên ngoài giao diện này, thì kết quả sẽ trả về bằng mã RESULT_CANCELED
. Ứng dụng của bạn cần xử lý cả hai khả năng này.
Đăng nhập bằng thông tin xác thực được truy xuất
Nếu người dùng chọn chia sẻ thông tin xác thực với ứng dụng của bạn, bạn có thể truy xuất thông tin đó bằng cách truyền dữ liệu ý định từ onActivityResult()
đến phương thức getSignInCredentialFromIntent()
của ứng dụng One Tap. Thông tin xác thực sẽ có thuộc tính googleIdToken
khác rỗng nếu người dùng đã chia sẻ thông tin xác thực 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 xác thực để 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 các thông tin đó để đăng nhập theo cách tương tự như khi người dùng cung cấp các thông tin đó theo cách thủ công.
Nếu bạn đã truy xuất thông tin xác thực Tài khoản Google, hãy sử dụng mã thông báo nhận dạng để xác thực với phần phụ trợ. Nếu bạn đã chọn sử dụng 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 bài viết Xác thực bằng phần phụ trợ bằng mã thông báo 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 One Tap
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 nhấn để không làm phiền người dùng bằng các lời nhắc lặp đi 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. Hoạt động này dùng thuộc tính đó để xác định xem có cung cấp tính năng Đăng nhập một lần 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 số phương thức khác.
Điều quan trọng là bạn phải triển khai giới hạn tốc độ của riêng mình đối với 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 One Tap 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 One Tap.
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 đăng nhập tự động, bước này vẫn rất quan trọng vì giúp đả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 mọi API Dịch vụ Play mà bạn sử dụng cũng được đặt lại.
Các bước tiếp theo
Nếu bạn đã định cấu hình ứng dụng One Tap để truy xuất thông tin xác thực của Google, thì ứng dụng của bạn hiện có thể nhận mã thông báo cho mã nhận dạng trên Google đại diện cho Tài khoản Google của người dùng. Tìm hiểu cách sử dụng các mã thông báo này ở phần phụ trợ.
Nếu hỗ trợ tính năng Đăng nhập bằng Google, bạn cũng có thể sử dụng ứng dụng One Tap để thêm quy trình tạo tài khoản liền mạch vào ứng dụng của mình.