Uwierzytelnij przez Apple na Androidzie

Aby umożliwić użytkownikom uwierzytelnianie się w Firebase za pomocą Apple ID, możesz użyć pakietu Firebase SDK do przeprowadzenia kompleksowego procesu logowania OAuth 2.0.

Zanim zaczniesz

Aby umożliwić użytkownikom logowanie się za pomocą Apple, najpierw skonfiguruj logowanie z Apple na stronie dewelopera Apple, a następnie włącz Apple jako dostawcę logowania w swoim projekcie Firebase.

Dołącz do Programu deweloperów Apple

Logowanie przez Apple może skonfigurować tylko osoba należąca do Programu dla deweloperów Apple.

Konfigurowanie logowania przez Apple

Na stronie Apple Developer wykonaj te czynności:

  1. Połącz witrynę z aplikacją zgodnie z opisem w pierwszej sekcji artykułu Konfigurowanie logowania z Apple w internecie. Gdy pojawi się taka 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 Firebase.

    Gdy skończysz, zanotuj nowy identyfikator usługi, którego będziesz potrzebować w następnej sekcji.

  2. Utwórz klucz prywatny „Zaloguj się przez Apple”. W następnej sekcji będziesz potrzebować nowego klucza prywatnego i identyfikatora klucza.
  3. Jeśli używasz funkcji Firebase Authentication, które wysyłają e-maile do użytkowników, w tym funkcji logowania za pomocą linku e-mail, weryfikacji adresu e-mail, zmiany konta i cofnięcia uprawnień, skonfiguruj prywatną usługę przekaźnika poczty e-mail Apple i zarejestruj noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (lub swoją niestandardową domenę szablonu e-maila), aby Apple mógł przekazywać e-maile wysyłane przez Firebase Authentication na anonimowe adresy e-mail Apple.

Włączanie logowania przez Apple jako dostawcy

  1. Dodaj Firebase do projektu na Androida. Pamiętaj, aby podczas konfigurowania aplikacji w konsoli Firebase zarejestrować jej podpis SHA-1.
  2. W konsoli Firebase otwórz sekcję Autoryzacja. Na karcie Metoda logowania włącz dostawcę Apple. Podaj identyfikator usługi utworzony w poprzedniej sekcji. W sekcji Konfiguracja procedury kodu OAuth podaj identyfikator zespołu Apple oraz klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.

Zapewnij zgodność z wymaganiami Apple dotyczącymi danych zanonimizowanych

Logowanie z 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 w domenie privaterelay.appleid.com. Jeśli w swojej aplikacji używasz funkcji Logowanie przez Apple, musisz przestrzegać wszystkich zasad lub warunków Apple dotyczących anonimowych identyfikatorów Apple.

Obejmuje to uzyskanie wymaganej zgody użytkownika przed powiązaniem jakichkolwiek danych osobowych umożliwiających bezpośrednią identyfikację z użyciem anonimowego identyfikatora Apple. Jeśli używasz Uwierzytelniania Firebase, może to obejmować te działania:

  • Połącz adres e-mail z anonimowym identyfikatorem Apple ID lub odwrotnie.
  • Łączenie numeru telefonu z utworzonym anonimowo identyfikatorem Apple ID lub na odwrót
  • Połącz nieanonimowe dane logowania do sieci społecznościowej (Facebook, Google itp.) z anonimowym identyfikatorem Apple ID lub odwrotnie.

Powyższa lista nie jest wyczerpująca. Aby sprawdzić, czy Twoja aplikacja spełnia wymagania Apple, zapoznaj się z Apple Developer Program License Agreement w sekcji Membership na koncie dewelopera.

Obsługa procesu logowania za pomocą pakietu SDK Firebase

Na Androidzie najłatwiej uwierzytelnić użytkowników za pomocą Firebase przy użyciu ich kont Apple, jeśli przekażesz cały proces logowania do pakietu SDK Firebase na Androida.

Aby obsłużyć proces logowania za pomocą pakietu Firebase Android SDK, wykonaj te czynności:

  1. Utwórz instancję OAuthProvider za pomocą kreatora z identyfikatorem dostawcy apple.com:

    Kotlin

    val provider = OAuthProvider.newBuilder("apple.com")
    

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    
  2. Opcjonalnie: określ dodatkowe zakresy OAuth 2.0 poza domyślnymi, które chcesz poprosić od dostawcy uwierzytelniania.

    Kotlin

    provider.setScopes(arrayOf("email", "name"))
    

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("email");
            add("name");
          }
        };
    provider.setScopes(scopes);
    

    Domyślnie, gdy włączona jest opcja Jedno konto na adres e-mail, Firebase prosi o zakresy adresów e-mail i nazwy. Jeśli zmienisz to ustawienie na Wiele kont na adres e-mail, Firebase nie będzie prosić Apple o żadne uprawnienia, chyba że je określisz.

  3. Opcjonalnie: jeśli chcesz wyświetlić ekran logowania Apple w języku innym niż angielski, ustaw parametr locale. Informacje o obsługiwanych lokalizacjach znajdziesz w dokumentacji logowania za pomocą 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");
    
  4. Uwierzytelnij się w Firebase, używając obiektu dostawcy OAuth. Pamiętaj, że w odróżnieniu od innych operacji FirebaseAuth ta spowoduje przejęcie kontroli nad interfejsem przez otwarcie niestandardowej karty Chrome. Dlatego nie odwołuj się do swojej aktywności w dołączonych elementach OnSuccessListenerOnFailureListener, ponieważ zostaną one natychmiast odłączone, gdy operacja uruchomi interfejs użytkownika.

    Najpierw sprawdź, czy nie dotarła do Ciebie już odpowiedź. Logowanie się w ten sposób powoduje, że Aktywność działa w tle, co oznacza, że system może ją przywrócić podczas procesu logowania. Aby uniknąć konieczności ponownego próbowania przez użytkownika, sprawdź, czy wynik już nie istnieje.

    Aby sprawdzić, czy nie ma oczekujących wyników, zadzwoń pod numer 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ących wyników, 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.

    Jeśli użytkownik nie chce udostępniać aplikacji swojego adresu e-mail, Apple udostępnia mu unikalny adres e-mail (w formie xyz@privaterelay.appleid.com), który przekazuje Twojej aplikacji. Jeśli skonfigurujesz prywatną usługę przekaźnika poczty e-mail, Apple przekierowuje e-maile wysłane na anonimowy adres na rzeczywisty adres e-mail użytkownika.

    Apple udostępnia aplikacjom informacje o użytkowniku, takie jak wyświetlana nazwa, tylko wtedy, gdy użytkownik zaloguje się po raz pierwszy. Zwykle Firebase przechowuje wyświetlaną nazwę podczas pierwszego logowania użytkownika za pomocą Apple. Możesz ją uzyskać za pomocą funkcji getCurrentUser().getDisplayName(). Jeśli jednak wcześniej zalogujesz użytkownika w aplikacji bez korzystania z Firebase, Apple nie przekaże Firebase jego imienia i nazwiska.

Ponowna weryfikacja i połączenie konta

Tego samego schematu można używać w przypadku startActivityForReauthenticateWithProvider(), aby pobrać nowe dane logowania na potrzeby 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 dotychczasowymi kontami.

Pamiętaj, że zanim połączysz konta użytkowników Apple z innymi danymi, musisz uzyskać ich wyraźną zgodę.

Aby na przykład połączyć konto Facebook z bieżącym kontem Firebase, użyj tokena dostępu uzyskanego po zalogowaniu 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 przetwarzanie procesu logowania

Możesz też uwierzytelnić się w Firebase za pomocą konta Apple, obsługując proces logowania za pomocą pakietu SDK Apple Sign-In JS, ręcznie tworząc proces OAuth lub używając biblioteki OAuth, np. AppAuth.

  1. W przypadku każdego żądania logowania generuj losowy ciąg znaków (zwany „nonce”), który pozwoli Ci sprawdzić, czy otrzymany token tożsamości został przyznany w odpowiedzi na żądanie uwierzytelniania aplikacji. Ten krok jest ważny, aby zapobiec atakom metodą powtórzenia.

    Na Androidzie możesz wygenerować zabezpieczony kryptograficznie nonce 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 uzyskaj hasz SHA246 nonce’a 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();
    }
    

    Wraz z żądaniem logowania wyślesz hasz SHA-256 wartości jednorazowej, który Apple przekaże bez zmian w odpowiedzi. Firebase weryfikuje odpowiedź, szyfrując pierwotny losowy ciąg znaków i porównując go z wartością przekazaną przez Apple.

  2. Zainicjuj proces logowania Apple za pomocą biblioteki OAuth lub innej metody. Pamiętaj, aby w żądaniu umieścić zaszyfrowany nonce jako parametr.

  3. Po otrzymaniu odpowiedzi od Apple pobierz z niej token identyfikacyjny i użyj go razem z niezaszyfrowanym nonce, aby utworzyć AuthCredential:

    Kotlin

    val credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build()
    

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    
  4. Uwierzytelnij się w Firebase, używając danych uwierzytelniających 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 metody signInWithCredential się powiedzie, możesz użyć metody getCurrentUser, aby pobrać dane konta użytkownika.

Unieważnienie tokena

Apple wymaga, aby aplikacje, które umożliwiają tworzenie kont, pozwalały użytkownikom na usunięcie konta z poziomu aplikacji zgodnie z opisem w wytycznych dotyczących weryfikacji App Store.

Aplikacje obsługujące logowanie przez Apple powinny też używać interfejsu REST API logowania przez Apple, aby cofać tokeny użytkowników.

Aby spełnić to wymaganie, wykonaj te czynności:

  1. Zaloguj się za pomocą metody startActivityForSignInWithProvider(), aby uzyskać AuthResult.

  2. Uzyskaj token dostępu dla dostawcy Apple.

    Kotlin

    val oauthCredential: OAuthCredential =  authResult.credential
    val accessToken = oauthCredential.accessToken
    

    Java

    OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential();
    String accessToken = oauthCredential.getAccessToken();
    
  3. Odwołaj token za pomocą interfejsu API revokeAccessToken.

    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 ...
              }
            }
      });
    
  1. Na koniec usuń konto użytkownika (i wszystkie powiązane dane).

    Dalsze kroki

    Gdy użytkownik zaloguje się po raz pierwszy, zostanie utworzone nowe konto użytkownika i połączone z danymi logowania, czyli nazwą użytkownika i hasłem, numerem telefonu lub informacjami dostawcy uwierzytelniania, za pomocą których użytkownik się zalogował. To 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 tego, jak użytkownik się loguje.

    • W swoich aplikacjach możesz pobrać podstawowe informacje o profilu użytkownika z obiektu FirebaseUser. Zobacz sekcję Zarządzanie użytkownikami.

    • W regułach Firebase Realtime DatabaseCloud Storage Regułach bezpieczeństwa możesz pobrać z zmiennej auth unikalny identyfikator zalogowanego użytkownika i używać go do kontrolowania dostępu użytkownika do danych.

    Możesz zezwolić użytkownikom na logowanie się w aplikacji za pomocą danych uwierzytelniających od różnych dostawców, łącząc je z dotychczasowym kontem użytkownika.

    Aby wylogować użytkownika, wywołaj funkcję signOut:

    Kotlin

    Firebase.auth.signOut()

    Java

    FirebaseAuth.getInstance().signOut();