Bạn có thể cho phép người dùng xác thực bằng Firebase bằng ID Apple của họ bằng cách sử dụng SDK Firebase để thực hiện luồng đăng nhập OAuth 2.0 từ đầu đến cuối.
Trước khi bắt đầu
Để đăng nhập người dùng bằng Apple, trước tiên hãy định cấu hình Đăng nhập bằng Apple trên trang web dành cho nhà phát triển của Apple, sau đó bật Apple làm nhà cung cấp dịch vụ đăng nhập cho dự án Firebase của bạn.
Tham gia Chương trình nhà phát triển của Apple
Đăng nhập bằng Apple chỉ có thể được cấu hình bởi các thành viên của Chương trình nhà phát triển Apple .
Định cấu hình Đăng nhập bằng Apple
Trên trang web Nhà phát triển Apple , hãy thực hiện như sau:
Liên kết trang web với ứng dụng của bạn như được mô tả trong phần đầu tiên của Định cấu hình Đăng nhập bằng Apple cho web . Khi được nhắc, hãy đăng ký URL sau làm URL trả về:
https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
Bạn có thể lấy ID dự án Firebase của mình trên trang cài đặt bảng điều khiển Firebase .
Khi bạn hoàn tất, hãy ghi lại ID dịch vụ mới của bạn, ID này bạn sẽ cần trong phần tiếp theo.
- Tạo Đăng nhập bằng khóa riêng của Apple . Bạn sẽ cần khóa riêng và ID khóa mới trong phần tiếp theo.
Nếu bạn sử dụng bất kỳ tính năng nào của Xác thực Firebase để gửi email cho người dùng, bao gồm đăng nhập liên kết email, xác minh địa chỉ email, thu hồi thay đổi tài khoản và các tính năng khác, hãy định cấu hình dịch vụ chuyển tiếp email riêng tư của Apple và đăng ký
noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com
(hoặc miền mẫu email tùy chỉnh của bạn) để Apple có thể chuyển tiếp các email được gửi bởi Xác thực Firebase đến các địa chỉ email Apple ẩn danh.
Cho phép Apple làm nhà cung cấp dịch vụ đăng nhập
- Thêm Firebase vào dự án Android của bạn . Hãy nhớ đăng ký chữ ký SHA-1 của ứng dụng khi bạn thiết lập ứng dụng của mình trong bảng điều khiển Firebase.
- Trong bảng điều khiển Firebase , hãy mở phần Xác thực . Trên tab Phương thức đăng nhập , kích hoạt nhà cung cấp Apple . Chỉ định ID dịch vụ bạn đã tạo ở phần trước. Ngoài ra, trong phần cấu hình luồng mã OAuth , hãy chỉ định ID nhóm Apple của bạn cũng như khóa riêng và ID khóa bạn đã tạo ở phần trước.
Tuân thủ các yêu cầu về dữ liệu ẩn danh của Apple
Đăng nhập bằng Apple cung cấp cho người dùng tùy chọn ẩn danh dữ liệu của họ, bao gồm cả địa chỉ email, khi đăng nhập. Người dùng chọn tùy chọn này có địa chỉ email có tên miền privaterelay.appleid.com
. Khi sử dụng Đăng nhập bằng Apple trong ứng dụng của mình, bạn phải tuân thủ mọi chính sách hoặc điều khoản hiện hành dành cho nhà phát triển từ Apple liên quan đến các ID Apple ẩn danh này.
Điều này bao gồm việc có được bất kỳ sự đồng ý cần thiết nào của người dùng trước khi bạn liên kết bất kỳ thông tin cá nhân nhận dạng trực tiếp nào với ID Apple ẩn danh. Khi sử dụng Xác thực Firebase, điều này có thể bao gồm các hành động sau:
- Liên kết địa chỉ email với ID Apple ẩn danh hoặc ngược lại.
- Liên kết số điện thoại với ID Apple ẩn danh hoặc ngược lại
- Liên kết thông tin xác thực xã hội không ẩn danh (Facebook, Google, v.v.) với ID Apple ẩn danh hoặc ngược lại.
Danh sách trên không toàn diện. Tham khảo Thỏa thuận cấp phép chương trình dành cho nhà phát triển của Apple trong phần Thành viên trong tài khoản nhà phát triển của bạn để đảm bảo ứng dụng của bạn đáp ứng các yêu cầu của Apple.
Xử lý luồng đăng nhập bằng SDK Firebase
Trên Android, cách dễ nhất để xác thực người dùng của bạn với Firebase bằng tài khoản Apple của họ là xử lý toàn bộ luồng đăng nhập bằng SDK Android của Firebase.
Để xử lý luồng đăng nhập bằng SDK Android Firebase, hãy làm theo các bước sau:
Tạo một phiên bản của
OAuthProvider
bằng cách sử dụng Trình tạo của nó với ID nhà cung cấpapple.com
:Kotlin+KTX
val provider = OAuthProvider.newBuilder("apple.com")
Java
OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
Tùy chọn: Chỉ định phạm vi OAuth 2.0 bổ sung ngoài phạm vi mặc định mà bạn muốn yêu cầu từ nhà cung cấp xác thực.
Kotlin+KTX
provider.setScopes(arrayOf("email", "name"))
Java
List<String> scopes = new ArrayList<String>() { { add("email"); add("name"); } }; provider.setScopes(scopes);
Theo mặc định, khi bật Một tài khoản cho mỗi địa chỉ email , Firebase sẽ yêu cầu phạm vi tên và email. Nếu bạn thay đổi cài đặt này thành Nhiều tài khoản trên mỗi địa chỉ email thì Firebase sẽ không yêu cầu bất kỳ phạm vi nào từ Apple trừ khi bạn chỉ định chúng.
Tùy chọn: Nếu bạn muốn hiển thị màn hình đăng nhập của Apple bằng ngôn ngữ khác tiếng Anh, hãy đặt tham số
locale
. Xem tài liệu Đăng nhập bằng Apple để biết các ngôn ngữ được hỗ trợ.Kotlin+KTX
// Localize the Apple authentication screen in French. provider.addCustomParameter("locale", "fr")
Java
// Localize the Apple authentication screen in French. provider.addCustomParameter("locale", "fr");
Xác thực với Firebase bằng đối tượng nhà cung cấp OAuth. Lưu ý rằng không giống như các hoạt động
FirebaseAuth
khác, thao tác này sẽ kiểm soát giao diện người dùng của bạn bằng cách mở Tab Chrome tùy chỉnh. Do đó, không tham chiếu Hoạt động của bạn trongOnSuccessListener
vàOnFailureListener
mà bạn đính kèm vì chúng sẽ tách ra ngay lập tức khi thao tác khởi động giao diện người dùng.Trước tiên bạn nên kiểm tra xem bạn đã nhận được phản hồi chưa. Việc đăng nhập bằng phương pháp này sẽ đặt Hoạt động của bạn ở chế độ nền, điều đó có nghĩa là hoạt động đó có thể được hệ thống thu hồi lại trong quá trình đăng nhập. Để đảm bảo rằng bạn không bắt người dùng thử lại nếu điều này xảy ra, bạn nên kiểm tra xem đã có kết quả chưa.
Để kiểm tra xem có kết quả đang chờ xử lý hay không, hãy gọi
getPendingAuthResult()
:Kotlin+KTX
val pending = auth.pendingAuthResult if (pending != null) { pending.addOnSuccessListener { authResult -> Log.d(TAG, "checkPending:onSuccess:$authResult") // Get the user profile with authResult.getUser() and // authResult.getAdditionalUserInfo(), and the ID // token from Apple with authResult.getCredential(). }.addOnFailureListener { e -> Log.w(TAG, "checkPending:onFailure", e) } } else { Log.d(TAG, "pending: null") }
Java
mAuth = FirebaseAuth.getInstance(); Task<AuthResult> pending = mAuth.getPendingAuthResult(); if (pending != null) { pending.addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { Log.d(TAG, "checkPending:onSuccess:" + authResult); // Get the user profile with authResult.getUser() and // authResult.getAdditionalUserInfo(), and the ID // token from Apple with authResult.getCredential(). } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.w(TAG, "checkPending:onFailure", e); } }); } else { Log.d(TAG, "pending: null"); }
Nếu không có kết quả đang chờ xử lý, hãy bắt đầu luồng đăng nhập bằng cách gọi
startActivityForSignInWithProvider()
:Kotlin+KTX
auth.startActivityForSignInWithProvider(this, provider.build()) .addOnSuccessListener { authResult -> // Sign-in successful! Log.d(TAG, "activitySignIn:onSuccess:${authResult.user}") val user = authResult.user // ... } .addOnFailureListener { e -> Log.w(TAG, "activitySignIn:onFailure", e) }
Java
mAuth.startActivityForSignInWithProvider(this, provider.build()) .addOnSuccessListener( new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Sign-in successful! Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser()); FirebaseUser user = authResult.getUser(); // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.w(TAG, "activitySignIn:onFailure", e); } });
Không giống như các nhà cung cấp khác được Firebase Auth hỗ trợ, Apple không cung cấp URL ảnh.
Ngoài ra, khi người dùng chọn không chia sẻ email của họ với ứng dụng, Apple sẽ cung cấp một địa chỉ email duy nhất cho người dùng đó (có dạng
xyz@privaterelay.appleid.com
) mà họ chia sẻ với ứng dụng của bạn. Nếu bạn đã định cấu hình dịch vụ chuyển tiếp email riêng tư, Apple sẽ chuyển tiếp các email được gửi đến địa chỉ ẩn danh tới địa chỉ email thực của người dùng.Apple chỉ chia sẻ thông tin người dùng như tên hiển thị với các ứng dụng trong lần đầu tiên người dùng đăng nhập. Thông thường, Firebase lưu trữ tên hiển thị trong lần đầu tiên người dùng đăng nhập bằng Apple. Bạn có thể lấy tên này bằng
getCurrentUser().getDisplayName()
. Tuy nhiên, nếu trước đây bạn đã sử dụng Apple để đăng nhập người dùng vào ứng dụng mà không sử dụng Firebase thì Apple sẽ không cung cấp cho Firebase tên hiển thị của người dùng.
Xác thực lại và liên kết tài khoản
Bạn có thể sử dụng mẫu tương tự với startActivityForReauthenticateWithProvider()
mà bạn có thể sử dụng để truy xuất thông tin xác thực mới cho các hoạt động nhạy cảm yêu cầu đăng nhập gần đây:
Kotlin+KTX
// The user is already signed-in.
val firebaseUser = auth.getCurrentUser()
firebaseUser
.startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
.addOnSuccessListener( authResult -> {
// User is re-authenticated with fresh tokens and
// should be able to perform sensitive operations
// like account deletion and email or password
// update.
})
.addOnFailureListener( e -> {
// Handle failure.
})
Java
// The user is already signed-in.
FirebaseUser firebaseUser = mAuth.getCurrentUser();
firebaseUser
.startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
.addOnSuccessListener(
new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
// User is re-authenticated with fresh tokens and
// should be able to perform sensitive operations
// like account deletion and email or password
// update.
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Handle failure.
}
});
Và bạn có thể sử dụng linkWithCredential()
để liên kết các nhà cung cấp danh tính khác nhau với các tài khoản hiện có.
Lưu ý rằng Apple yêu cầu bạn phải nhận được sự đồng ý rõ ràng từ người dùng trước khi liên kết tài khoản Apple của họ với dữ liệu khác.
Ví dụ: để liên kết tài khoản Facebook với tài khoản Firebase hiện tại, hãy sử dụng mã thông báo truy cập bạn nhận được khi đăng nhập người dùng vào Facebook:
Kotlin+KTX
// Initialize a Facebook credential with a Facebook access token.
val credential = FacebookAuthProvider.getCredential(token.getToken())
// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, task -> {
if (task.isSuccessful()) {
// Facebook credential is linked to the current Apple user.
// The user can now sign in to the same account
// with either Apple or Facebook.
}
});
Java
// Initialize a Facebook credential with a Facebook access token.
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Facebook credential is linked to the current Apple user.
// The user can now sign in to the same account
// with either Apple or Facebook.
}
}
});
Nâng cao: Xử lý luồng đăng nhập theo cách thủ công
Bạn cũng có thể xác thực với Firebase bằng Tài khoản Apple bằng cách xử lý luồng đăng nhập bằng cách sử dụng SDK JS đăng nhập của Apple, xây dựng luồng OAuth theo cách thủ công hoặc bằng cách sử dụng thư viện OAuth như AppAuth .
Đối với mỗi yêu cầu đăng nhập, hãy tạo một chuỗi ngẫu nhiên—một chuỗi "nonce"—mà bạn sẽ sử dụng để đảm bảo mã thông báo ID bạn nhận được được cấp cụ thể để đáp ứng yêu cầu xác thực của ứng dụng của bạn. Bước này rất quan trọng để ngăn chặn các cuộc tấn công lặp lại.
Bạn có thể tạo nonce bảo mật bằng mật mã trên Android bằng
SecureRandom
, như trong ví dụ sau:Kotlin+KTX
private fun generateNonce(length: Int): String { val generator = SecureRandom() val charsetDecoder = StandardCharsets.US_ASCII.newDecoder() charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE) charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE) val bytes = ByteArray(length) val inBuffer = ByteBuffer.wrap(bytes) val outBuffer = CharBuffer.allocate(length) while (outBuffer.hasRemaining()) { generator.nextBytes(bytes) inBuffer.rewind() charsetDecoder.reset() charsetDecoder.decode(inBuffer, outBuffer, false) } outBuffer.flip() return outBuffer.toString() }
Java
private String generateNonce(int length) { SecureRandom generator = new SecureRandom(); CharsetDecoder charsetDecoder = StandardCharsets.US_ASCII.newDecoder(); charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE); charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE); byte[] bytes = new byte[length]; ByteBuffer inBuffer = ByteBuffer.wrap(bytes); CharBuffer outBuffer = CharBuffer.allocate(length); while (outBuffer.hasRemaining()) { generator.nextBytes(bytes); inBuffer.rewind(); charsetDecoder.reset(); charsetDecoder.decode(inBuffer, outBuffer, false); } outBuffer.flip(); return outBuffer.toString(); }
Sau đó, lấy hàm băm SHA246 của số nonce dưới dạng chuỗi hex:
Kotlin+KTX
private fun sha256(s: String): String { val md = MessageDigest.getInstance("SHA-256") val digest = md.digest(s.toByteArray()) val hash = StringBuilder() for (c in digest) { hash.append(String.format("%02x", c)) } return hash.toString() }
Java
private String sha256(String s) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(s.getBytes()); StringBuilder hash = new StringBuilder(); for (byte c: digest) { hash.append(String.format("%02x", c)); } return hash.toString(); }
Bạn sẽ gửi hàm băm SHA256 của nonce cùng với yêu cầu đăng nhập của mình và Apple sẽ chuyển yêu cầu này không thay đổi trong phản hồi. Firebase xác thực phản hồi bằng cách băm số nonce ban đầu và so sánh nó với giá trị được Apple chuyển.
Bắt đầu luồng đăng nhập của Apple bằng thư viện OAuth của bạn hoặc phương pháp khác. Hãy đảm bảo bao gồm số nonce đã băm làm tham số trong yêu cầu của bạn.
Sau khi bạn nhận được phản hồi của Apple, hãy lấy mã thông báo ID từ phản hồi và sử dụng nó cũng như số nonce chưa được băm để tạo
AuthCredential
:Kotlin+KTX
val credential = OAuthProvider.newCredentialBuilder("apple.com") .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce) .build()
Java
AuthCredential credential = OAuthProvider.newCredentialBuilder("apple.com") .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce) .build();
Xác thực với Firebase bằng thông tin xác thực Firebase:
Kotlin+KTX
auth.signInWithCredential(credential) .addOnCompleteListener(this) { task -> if (task.isSuccessful) { // User successfully signed in with Apple ID token. // ... } }
Java
mAuth.signInWithCredential(credential) .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // User successfully signed in with Apple ID token. // ... } } });
Nếu lệnh gọi signInWithCredential
thành công, bạn có thể sử dụng phương thức getCurrentUser
để lấy dữ liệu tài khoản của người dùng.
Thu hồi mã thông báo
Apple yêu cầu các ứng dụng hỗ trợ tạo tài khoản phải cho phép người dùng bắt đầu xóa tài khoản của họ trong ứng dụng, như được mô tả trong Nguyên tắc đánh giá của App Store
Ngoài ra, các ứng dụng hỗ trợ Đăng nhập bằng Apple nên sử dụng API REST đăng nhập bằng Apple để thu hồi mã thông báo của người dùng.
Để đáp ứng yêu cầu này, hãy thực hiện các bước sau:
Sử dụng phương thức
startActivityForSignInWithProvider()
để đăng nhập bằng Apple và nhậnAuthResult
.Nhận mã thông báo truy cập cho nhà cung cấp Apple.
Kotlin+KTX
val oauthCredential: OAuthCredential = authResult.credential val accessToken = oauthCredential.accessToken
Java
OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential(); String accessToken = oauthCredential.getAccessToken();
Thu hồi mã thông báo bằng API
revokeAccessToken
.Kotlin+KTX
mAuth.revokeAccessToken(accessToken) .addOnCompleteListener(this) { task -> if (task.isSuccessful) { // Access token successfully revoked // for the user ... } }
Java
mAuth.revokeAccessToken(accessToken) .addOnCompleteListener(this, new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { // Access token successfully revoked // for the user ... } } });
- Cuối cùng, xóa tài khoản người dùng (và tất cả dữ liệu liên quan)
Bước tiếp theo
Sau khi người dùng đăng nhập lần đầu tiên, một tài khoản người dùng mới sẽ được tạo và liên kết với thông tin xác thực—tức là tên người dùng và mật khẩu, số điện thoại hoặc thông tin nhà cung cấp dịch vụ xác thực—mà người dùng đã đăng nhập. Tài khoản mới này được lưu trữ như một phần của dự án Firebase của bạn và có thể được sử dụng để xác định người dùng trên mọi ứng dụng trong dự án của bạn, bất kể người dùng đăng nhập bằng cách nào.
Trong ứng dụng của mình, bạn có thể lấy thông tin hồ sơ cơ bản của người dùng từ đối tượng
FirebaseUser
. Xem Quản lý người dùng .Trong Quy tắc bảo mật cơ sở dữ liệu thời gian thực và lưu trữ đám mây của Firebase, bạn có thể lấy ID người dùng duy nhất của người dùng đã đăng nhập từ biến
auth
và sử dụng nó để kiểm soát dữ liệu nào người dùng có thể truy cập.
Bạn có thể cho phép người dùng đăng nhập vào ứng dụng của mình bằng nhiều nhà cung cấp xác thực bằng cách liên kết thông tin xác thực của nhà cung cấp xác thực với tài khoản người dùng hiện có.
Để đăng xuất người dùng, hãy gọi
signOut
:Kotlin+KTX
Firebase.auth.signOut()
Java
FirebaseAuth.getInstance().signOut();