Możesz zezwolić użytkownikom na uwierzytelnianie w Firebase za pomocą Apple ID, korzystając z pakietu Firebase SDK do przeprowadzania kompleksowego procesu logowania OAuth 2.0.
Zanim zaczniesz
Aby logować użytkowników za pomocą Apple, najpierw skonfiguruj logowanie przez Apple na stronie dla deweloperów Apple, a potem włącz Apple jako dostawcę logowania w projekcie Firebase.
Dołączanie do programu Apple Developer Program
Logowanie przez Apple mogą konfigurować tylko uczestnicy programu Apple Developer.
Konfigurowanie logowania się przez Apple
Na stronie Apple Developer wykonaj te czynności:
-
Powiąż swoją witrynę z aplikacją zgodnie z opisem w pierwszej sekcji artykułu Konfigurowanie logowania za pomocą Apple w internecie. Gdy pojawi się prośba, zarejestruj ten adres URL jako powrotny adres URL:
https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
Identyfikator projektu Firebase znajdziesz na stronie ustawień Firebase konsoli.
Gdy skończysz, zanotuj nowy identyfikator usługi, który będzie Ci potrzebny w następnej sekcji.
- Utwórz klucz prywatny funkcji Zaloguj się przez Apple. W następnej sekcji będziesz potrzebować nowego klucza prywatnego i identyfikatora klucza.
-
Jeśli korzystasz z funkcji Firebase Authentication, które wysyłają e-maile do użytkowników, w tym logowania za pomocą linku w e-mailu, weryfikacji adresu e-mail, wycofania zmiany konta i innych, skonfiguruj prywatną usługę przekaźnika poczty e-mail Apple i zarejestruj
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com
(lub dostosowaną domenę szablonu e-maila), aby Apple mogło przekazywać e-maile wysyłane przez Firebase Authentication na anonimowe adresy e-mail Apple.
Włączanie Apple jako dostawcy logowania
- Dodaj Firebase do projektu na Androida. Podczas konfigurowania aplikacji w Firebase konsoli zarejestruj podpis SHA-1 aplikacji.
- W Firebasekonsoli otwórz sekcję Uwierzytelnianie. Na karcie Metoda logowania włącz dostawcę Apple. Określ identyfikator usługi utworzony w poprzedniej sekcji. W sekcji konfiguracji procesu OAuth podaj też identyfikator zespołu Apple, klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.
Zapewnianie zgodności z wymaganiami Apple dotyczącymi danych anonimizowanych
Logowanie przez Apple umożliwia użytkownikom anonimizację danych, w tym adresu e-mail, podczas logowania. Użytkownicy, którzy wybiorą tę opcję, będą mieć adresy e-mail z domeną privaterelay.appleid.com
. Jeśli w aplikacji używasz funkcji Zaloguj się przez Apple, musisz przestrzegać wszelkich obowiązujących zasad lub warunków dla deweloperów firmy Apple dotyczących tych zanonimizowanych identyfikatorów Apple.
Obejmuje to uzyskanie wymaganej zgody użytkownika przed powiązaniem bezpośrednio identyfikujących danych osobowych z zanonimizowanym identyfikatorem Apple ID. W przypadku korzystania z Uwierzytelniania Firebase mogą to być te działania:
- Połącz adres e-mail z anonimizowanym identyfikatorem Apple ID lub odwrotnie.
- Łączenie numeru telefonu z zanonimizowanym identyfikatorem Apple ID i odwrotnie
- połączenie nieanonimowych danych logowania w usługach społecznościowych (Facebook, Google itp.) ze zanonimizowanym identyfikatorem Apple ID lub odwrotnie;
Powyższa lista nie jest wyczerpująca. Zapoznaj się z umową licencyjną programu Apple Developer Program w sekcji Członkostwo na koncie dewelopera, aby upewnić się, że Twoja aplikacja spełnia wymagania Apple.
Obsługa procesu logowania za pomocą pakietu Firebase SDK
Na Androidzie najprostszym sposobem uwierzytelniania użytkowników w Firebase za pomocą kont Apple jest obsługa całego procesu logowania za pomocą pakietu Firebase Android SDK.
Aby obsłużyć proces logowania za pomocą pakietu Firebase Android SDK, wykonaj te czynności:
Utwórz instancję
OAuthProvider
za pomocą jej narzędzia do tworzenia z identyfikatorem dostawcyapple.com
:Kotlin
val provider = OAuthProvider.newBuilder("apple.com")
Java
OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
Opcjonalnie: określ dodatkowe zakresy OAuth 2.0 poza domyślnymi, o które chcesz poprosić dostawcę uwierzytelniania.
Kotlin
provider.setScopes(arrayOf("email", "name"))
Java
List<String> scopes = new ArrayList<String>() { { add("email"); add("name"); } }; provider.setScopes(scopes);
Gdy opcja Jedno konto na każdy adres e-mail jest włączona, Firebase domyślnie wysyła prośby o zakresy adresu e-mail i imienia. Jeśli zmienisz to ustawienie na Wiele kont na adres e-mail, Firebase nie będzie wysyłać do Apple żadnych zakresów, chyba że je określisz.
Opcjonalnie: jeśli chcesz, aby ekran logowania Apple był wyświetlany w języku innym niż angielski, ustaw parametr
locale
. Listę obsługiwanych ustawień regionalnych znajdziesz w dokumentacji Logowania przez Apple.Kotlin
// Localize the Apple authentication screen in French. provider.addCustomParameter("locale", "fr")
Java
// Localize the Apple authentication screen in French. provider.addCustomParameter("locale", "fr");
Uwierzytelnij w Firebase za pomocą obiektu dostawcy OAuth. Pamiętaj, że w przeciwieństwie do innych operacji
FirebaseAuth
ta przejmie kontrolę nad interfejsem, otwierając niestandardową kartę Chrome. W związku z tym nie odwołuj się do aktywności wOnSuccessListener
iOnFailureListener
, które dołączasz, ponieważ zostaną one natychmiast odłączone, gdy operacja uruchomi interfejs.Najpierw sprawdź, czy nie otrzymano już odpowiedzi. Logowanie tą metodą powoduje przeniesienie aktywności w tle, co oznacza, że system może ją odzyskać podczas procesu logowania. Aby uniknąć sytuacji, w której użytkownik musi ponownie spróbować, sprawdź, czy wynik jest już dostępny.
Aby sprawdzić, czy jest oczekiwany wynik, wywołaj funkcję
getPendingAuthResult()
:Kotlin
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"); }
Jeśli nie ma oczekującego wyniku, rozpocznij proces logowania, wywołując
startActivityForSignInWithProvider()
:Kotlin
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); } });
W przeciwieństwie do innych dostawców obsługiwanych przez Firebase Auth Apple nie udostępnia adresu URL zdjęcia.
Gdy użytkownik zdecyduje się nie udostępniać aplikacji swojego adresu e-mail, Apple udostępnia mu unikalny adres e-mail (w formacie
xyz@privaterelay.appleid.com
), który jest udostępniany Twojej aplikacji. Jeśli skonfigurujesz usługę przekaźnika prywatnego adresu e-mail, Apple będzie przekazywać e-maile wysyłane na anonimowy adres na prawdziwy adres e-mail użytkownika.Apple udostępnia aplikacjom informacje o użytkowniku, takie jak nazwa wyświetlana, tylko przy pierwszym logowaniu. Zwykle Firebase zapisuje nazwę wyświetlaną przy pierwszym logowaniu użytkownika za pomocą Apple. Możesz ją uzyskać za pomocą
getCurrentUser().getDisplayName()
. Jeśli jednak wcześniej użytkownik logował się w aplikacji za pomocą Apple bez użycia Firebase, Apple nie przekaże Firebase nazwy wyświetlanej użytkownika.
Ponowne uwierzytelnianie i łączenie kont
Tego samego wzorca można użyć w przypadku funkcji startActivityForReauthenticateWithProvider()
która umożliwia pobranie nowych danych logowania do operacji związanych z poufnymi danymi, które
wymagają niedawnego zalogowania:
Kotlin
// 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.
}
});
Możesz też użyć linkWithCredential()
, aby połączyć różnych dostawców tożsamości z istniejącymi kontami.
Pamiętaj, że firma Apple wymaga uzyskania wyraźnej zgody użytkowników przed połączeniem ich kont Apple z innymi danymi.
Aby na przykład połączyć konto Facebook z bieżącym kontem Firebase, użyj tokena dostępu uzyskanego podczas logowania użytkownika na Facebooku:
Kotlin
// 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.
}
}
});
Zaawansowane: ręczne obsługiwanie procesu logowania
Możesz też uwierzytelniać się w Firebase za pomocą konta Apple, obsługując proces logowania za pomocą pakietu Apple Sign-In JS SDK, ręcznie tworząc proces OAuth lub używając biblioteki OAuth, takiej jak AppAuth.
W przypadku każdego żądania logowania wygeneruj losowy ciąg znaków – „nonce” – który posłuży Ci do sprawdzenia, czy otrzymany token identyfikatora został przyznany w odpowiedzi na żądanie uwierzytelniania aplikacji. Ten krok jest ważny, aby zapobiec atakom metodą powtórzenia.
Możesz wygenerować bezpieczny kryptograficznie jednorazowy ciąg znaków w Androidzie za pomocą funkcji
SecureRandom
, jak w tym przykładzie:Kotlin
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(); }
Następnie pobierz hash SHA256 nonce jako ciąg szesnastkowy:
Kotlin
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(); }
W żądaniu logowania wyślesz identyfikator SHA256 wartości jednorazowej, który Apple przekaże w odpowiedzi bez zmian. Firebase weryfikuje odpowiedź, haszując oryginalny nonce i porównując go z wartością przekazaną przez Apple.
Uruchom proces logowania Apple za pomocą biblioteki OAuth lub innej metody. Pamiętaj, aby w żądaniu uwzględnić zaszyfrowany ciąg nonce jako parametr.
Po otrzymaniu odpowiedzi od Apple pobierz z niej token identyfikatora i użyj go oraz niezaszyfrowanego nonce do utworzenia
AuthCredential
:Kotlin
val credential = OAuthProvider.newCredentialBuilder("apple.com") .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce) .build()
Java
AuthCredential credential = OAuthProvider.newCredentialBuilder("apple.com") .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce) .build();
Uwierzytelnij się w Firebase za pomocą danych logowania Firebase:
Kotlin
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. // ... } } });
Jeśli wywołanie signInWithCredential
się powiedzie, możesz użyć metody getCurrentUser
, aby uzyskać dane konta użytkownika.
Unieważnienie tokena
Zgodnie z wytycznymi dotyczącymi weryfikacji aplikacji w App Store firma Apple wymaga, aby aplikacje, które umożliwiają tworzenie kont, pozwalały użytkownikom na rozpoczęcie procesu usuwania konta w aplikacji.
Aplikacje, które obsługują logowanie za pomocą Apple, powinny używać interfejsu Sign in with Apple REST API do unieważniania tokenów użytkowników.
Aby spełnić to wymaganie, wykonaj te czynności:
Użyj metody
startActivityForSignInWithProvider()
, aby zalogować się za pomocą Apple i uzyskaćAuthResult
.Uzyskaj token dostępu dostawcy Apple.
Kotlin
val oauthCredential: OAuthCredential = authResult.credential val accessToken = oauthCredential.accessToken
Java
OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential(); String accessToken = oauthCredential.getAccessToken();
Odwołaj token za pomocą interfejsu
revokeAccessToken
API.Kotlin
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 ... } } });
- Na koniec usuń konto użytkownika (i wszystkie powiązane z nim dane).
Dalsze kroki
Gdy użytkownik zaloguje się po raz pierwszy, zostanie utworzone nowe konto użytkownika i powiązane z danymi logowania, czyli nazwą użytkownika i hasłem, numerem telefonu lub informacjami o dostawcy uwierzytelniania, za pomocą których użytkownik się zalogował. Nowe konto jest przechowywane w projekcie Firebase i może służyć do identyfikowania użytkownika we wszystkich aplikacjach w projekcie, niezależnie od sposobu logowania.
-
W aplikacjach możesz uzyskać podstawowe informacje o profilu użytkownika z obiektu
FirebaseUser
. Zobacz Zarządzanie użytkownikami. W Firebase Realtime Database i Cloud Storage regułach bezpieczeństwa możesz pobrać unikalny identyfikator zalogowanego użytkownika ze zmiennej
auth
i użyć go do kontrolowania, do jakich danych użytkownik ma dostęp.
Możesz zezwolić użytkownikom na logowanie się w aplikacji za pomocą wielu dostawców uwierzytelniania, łącząc dane logowania dostawcy uwierzytelniania z istniejącym kontem użytkownika.
Aby wylogować użytkownika, wywołaj funkcję
signOut
:Kotlin
Firebase.auth.signOut()
Java
FirebaseAuth.getInstance().signOut();
-