Tính năng Đăng nhập bằng tài khoản được liên kết bật tính năng Đăng nhập bằng một lần chạm bằng Google cho người dùng đã liên kết Tài khoản Google của họ với dịch vụ của bạn. Điều này giúp cải thiện trải nghiệm cho người dùng vì họ có thể đăng nhập bằng một cú nhấp chuột mà không cần nhập lại tên người dùng và mật khẩu của mình. Điều này cũng làm giảm cơ hội người dùng tạo tài khoản trùng lặp trên dịch vụ của bạn.
Tính năng Đăng nhập bằng tài khoản được liên kết được cung cấp trong quy trình Đăng nhập bằng một lần chạm cho Android. Điều này có nghĩa là bạn không cần nhập thư viện riêng nếu ứng dụng của bạn đã bật tính năng Một lần chạm.
Trong tài liệu này, bạn sẽ tìm hiểu cách sửa đổi ứng dụng Android để hỗ trợ Đăng nhập bằng tài khoản được liên kết.
Cách hoạt động
- Bạn chọn hiển thị các tài khoản được liên kết trong quy trình Đăng nhập bằng một lần chạm.
- Nếu người dùng đã đăng nhập trên Google và đã liên kết Tài khoản Google của họ với tài khoản của họ trên dịch vụ của bạn, thì một mã thông báo nhận dạng sẽ được trả về cho tài khoản.
- Người dùng nhìn thấy lời nhắc đăng nhập bằng một lần chạm với lựa chọn đăng nhập vào với tài khoản được liên kết của họ.
- Nếu người dùng chọn tiếp tục với tài khoản được liên kết, mã thông báo ID của người dùng sẽ được trả về ứng dụng của bạn. Bạn so khớp mã này với mã thông báo đã được gửi đến máy chủ ở bước 2 để xác định người dùng đã đăng nhập.
Thiết lập
Thiết lập môi trường phát triển
Tải các dịch vụ mới nhất của Dịch vụ Google Play trên máy chủ phát triển của bạn:
Trong phần SDK Tools (Bộ công cụ SDK), hãy tìm Dịch vụ Google Play.
Nếu trạng thái của các gói này là chưa Cài đặt, hãy chọn cả hai rồi nhấp vào Cài đặt gói.
Định cấu hình ứng dụng
Trong tệp
build.gradle
cấp dự án, hãy thêm kho lưu trữ Maven của Google trong cả hai phầnbuildscript
vàallprojects
.buildscript { repositories { google() } } allprojects { repositories { google() } }
Thêm phần phụ thuộc cho đường liên kết "Liên kết với Google" API cho mô-đun của bạn tệp gradle cấp ứng dụng, thường là
app/build.gradle
:dependencies { implementation 'com.google.android.gms:play-services-auth:21.2.0' }
Sửa đổi ứng dụng Android để hỗ trợ tính năng Đăng nhập bằng tài khoản được liên kết
Ở cuối quy trình Đăng nhập vào tài khoản được liên kết, mã thông báo ID sẽ được trả về cho . Bạn phải xác minh tính toàn vẹn của mã thông báo mã nhận dạng trước khi đăng nhập người dùng.
Mã mẫu sau đây trình bày chi tiết các bước truy xuất, xác minh mã thông báo nhận dạng, sau đó đăng nhập cho người dùng đó.
Tạo một hoạt động để nhận kết quả của Ý định đăng nhập
Kotlin
private val activityResultLauncher = registerForActivityResult( ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode == RESULT_OK) { try { val signInCredentials = Identity.signInClient(this) .signInCredentialFromIntent(result.data) // Review the Verify the integrity of the ID token section for // details on how to verify the ID token verifyIdToken(signInCredential.googleIdToken) } catch (e: ApiException) { Log.e(TAG, "Sign-in failed with error code:", e) } } else { Log.e(TAG, "Sign-in failed") } }
Java
private final ActivityResultLauncher<IntentSenderResult> activityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), result -> { If (result.getResultCode() == RESULT_OK) { try { SignInCredential signInCredential = Identity.getSignInClient(this) .getSignInCredentialFromIntent(result.getData()); verifyIdToken(signInCredential.getGoogleIdToken()); } catch (e: ApiException ) { Log.e(TAG, "Sign-in failed with error:", e) } } else { Log.e(TAG, "Sign-in failed") } });
Tạo yêu cầu đăng nhập
Kotlin
private val tokenRequestOptions = GoogleIdTokenRequestOptions.Builder() .supported(true) // Your server's client ID, not your Android client ID. .serverClientId(getString("your-server-client-id") .filterByAuthorizedAccounts(true) .associateLinkedAccounts("service-id-of-and-defined-by-developer", scopes) .build()
Java
private final GoogleIdTokenRequestOptions tokenRequestOptions = GoogleIdTokenRequestOptions.Builder() .setSupported(true) .setServerClientId("your-service-client-id") .setFilterByAuthorizedAccounts(true) .associateLinkedAccounts("service-id-of-and-defined-by-developer", scopes) .build()
Chạy ý định đang chờ đăng nhập
Kotlin
Identity.signInClient(this) .beginSignIn( BeginSignInRequest.Builder() .googleIdTokenRequestOptions(tokenRequestOptions) .build()) .addOnSuccessListener{result -> activityResultLauncher.launch(result.pendingIntent.intentSender) } .addOnFailureListener {e -> Log.e(TAG, "Sign-in failed because:", e) }
Java
Identity.getSignInClient(this) .beginSignIn( BeginSignInRequest.Builder() .setGoogleIdTokenRequestOptions(tokenRequestOptions) .build()) .addOnSuccessListener(result -> { activityResultLauncher.launch( result.getPendingIntent().getIntentSender()); }) .addOnFailureListener(e -> { Log.e(TAG, "Sign-in failed because:", e); });
Xác minh tính toàn vẹn của mã thông báo mã nhận dạng
Để xác minh mã thông báo là hợp lệ, hãy đảm bảo rằng: tiêu chí được đáp ứng:
- Mã thông báo nhận dạng đã được Google ký đúng cách. Sử dụng khoá công khai của Google
(có sẵn bằng
JWK hoặc
định dạng PEM)
để xác minh chữ ký của mã thông báo. Các khoá này được xoay vòng thường xuyên; kiểm tra
tiêu đề
Cache-Control
trong phản hồi để xác định thời điểm bạn nên truy xuất lại chúng. - Giá trị của
aud
trong mã thông báo nhận dạng bằng một trong các giá trị của ứng dụng khách hàng. Quy trình kiểm tra này là cần thiết để ngăn chặn mã thông báo nhận dạng được cấp cho dùng để truy cập vào dữ liệu về cùng một người dùng trên máy chủ phụ trợ của ứng dụng. - Giá trị của
iss
trong mã thông báo nhận dạng bằngaccounts.google.com
hoặchttps://accounts.google.com
. - Chưa hết thời gian hết hạn (
exp
) của mã thông báo giá trị nhận dạng. - Trường hợp bạn cần xác thực rằng mã thông báo mã nhận dạng đại diện cho Google Workspace hoặc Cloud
tài khoản tổ chức của mình, bạn có thể kiểm tra xác nhận quyền sở hữu
hd
, cho biết của người dùng. Phải sử dụng chế độ này khi hạn chế quyền truy cập vào tài nguyên chỉ cho các thành viên của một số miền nhất định. Việc không có xác nhận quyền sở hữu này cho thấy rằng tài khoản đó không thuộc về Tên miền do Google lưu trữ.
Bằng cách sử dụng các trường email
, email_verified
và hd
, bạn có thể xác định xem
Google lưu trữ và có thẩm quyền đối với một địa chỉ email. Trong trường hợp Google có thẩm quyền,
người dùng được xác định là chủ sở hữu tài khoản hợp pháp và bạn có thể bỏ qua mật khẩu hoặc
thử thách.
Những trường hợp mà Google có thẩm quyền:
email
có hậu tố@gmail.com
, đây là một tài khoản Gmail.email_verified
là đúng vàhd
đã được đặt, đây là tài khoản G Suite.
Người dùng có thể đăng ký Tài khoản Google mà không cần sử dụng Gmail hoặc G Suite. Thời gian
email
không chứa hậu tố @gmail.com
và không có hd
, Google thì không
xác thực và sử dụng mật khẩu hoặc các phương pháp xác thực khác để xác minh
người dùng. email_verified
cũng có thể đúng vì ban đầu Google đã xác minh
người dùng khi tài khoản Google được tạo, tuy nhiên quyền sở hữu đối với bên thứ ba
tài khoản email có thể đã thay đổi.
Thay vì tự viết mã để thực hiện các bước xác minh này, chúng tôi
đề xuất sử dụng thư viện ứng dụng Google API cho nền tảng của bạn hoặc cho một mục đích chung
Thư viện JWT. Để phát triển và gỡ lỗi, bạn có thể gọi tokeninfo
điểm cuối xác thực.
Sử dụng Thư viện ứng dụng API của Google
Sử dụng Thư viện ứng dụng Java API của Google bạn nên áp dụng để xác thực mã thông báo mã nhận dạng Google trong môi trường phát hành chính thức.
Java
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
...
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
// Specify the CLIENT_ID of the app that accesses the backend:
.setAudience(Collections.singletonList(CLIENT_ID))
// Or, if multiple clients access the backend:
//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
.build();
// (Receive idTokenString by HTTPS POST)
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
} else {
System.out.println("Invalid ID token.");
}
Phương thức GoogleIdTokenVerifier.verify()
xác minh chữ ký JWT,
Thông báo xác nhận quyền sở hữu aud
, thông báo xác nhận quyền sở hữu iss
và thông báo xác nhận quyền sở hữuexp
.
Trường hợp bạn cần xác thực rằng mã thông báo mã nhận dạng đại diện cho Google Workspace hoặc Cloud
tài khoản tổ chức, bạn có thể xác minh thông báo xác nhận quyền sở hữu hd
bằng cách kiểm tra tên miền
được phương thức Payload.getHostedDomain()
trả về.
Gọi điểm cuối tokeninfo
Một cách dễ dàng để xác thực chữ ký mã thông báo mã nhận dạng cho việc gỡ lỗi là sử dụng điểm cuối tokeninfo
. Việc gọi điểm cuối này sẽ bao gồm một yêu cầu mạng bổ sung giúp thực hiện hầu hết quy trình xác thực cho bạn trong khi bạn kiểm thử việc xác thực và trích xuất tải trọng phù hợp trong mã của riêng bạn. API này không phù hợp để sử dụng trong mã phát hành chính thức vì yêu cầu có thể bị điều tiết hoặc gặp lỗi không liên tục.
Để xác thực mã thông báo mã nhận dạng bằng điểm cuối tokeninfo
, hãy gửi yêu cầu POST hoặc GET HTTPS đến điểm cuối rồi chuyển mã thông báo mã nhận dạng của bạn vào tham số id_token
.
Ví dụ: để xác thực mã thông báo "XYZ123", hãy thực hiện yêu cầu GET sau:
https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123
Nếu mã thông báo được ký đúng cách cũng như các thông báo xác nhận quyền sở hữu iss
và exp
có giá trị dự kiến, thì bạn sẽ nhận được phản hồi HTTP 200, trong đó phần nội dung chứa các thông báo xác nhận quyền sở hữu mã thông báo có định dạng JSON.
Sau đây là câu trả lời mẫu:
{ // These six fields are included in all Google ID Tokens. "iss": "https://accounts.google.com", "sub": "110169484474386276334", "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "iat": "1433978353", "exp": "1433981953", // These seven fields are only included when the user has granted the "profile" and // "email" OAuth scopes to the application. "email": "testuser@gmail.com", "email_verified": "true", "name" : "Test User", "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg", "given_name": "Test", "family_name": "User", "locale": "en" }
Nếu cần xác thực rằng mã thông báo nhận dạng đại diện cho một tài khoản Google Workspace, bạn có thể kiểm tra thông báo xác nhận quyền sở hữu hd
. Thông báo này cho biết miền mà người dùng lưu trữ. Bạn phải dùng tính năng này khi chỉ cho phép các thành viên của một số miền nhất định truy cập vào tài nguyên. Nếu không có khiếu nại này,
tài khoản đó không thuộc một miền do Google Workspace lưu trữ.