Uwierzytelnianie za pomocą Apple na Androidzie

Możesz pozwolić użytkownikom na uwierzytelnianie w Firebase za pomocą identyfikatora Apple ID, korzystając z pakietu SDK Firebase, który przeprowadzi kompleksowy proces logowania się za pomocą protokołu OAuth 2.0.

Zanim zaczniesz

Aby zalogować użytkowników za pomocą konta Apple, najpierw w witrynie dla deweloperów Apple skonfiguruj funkcję Zaloguj się przez Apple, a potem włącz Apple jako dostawcę logowania w projekcie Firebase.

Dołącz do programu Apple dla deweloperów

Funkcję Zaloguj się przez Apple mogą skonfigurować tylko uczestnicy programu Apple dla deweloperów.

Konfigurowanie logowania przez Apple

W witrynie Apple Developers wykonaj te czynności:

  1. Powiąż swoją witrynę z aplikacją zgodnie z opisem w pierwszej sekcji artykułu Konfigurowanie logowania się przez Apple w internecie. Gdy pojawi się prośba, zarejestruj ten adres URL jako zwrotny adres URL:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    Identyfikator projektu Firebase znajdziesz na stronie ustawień konsoli Firebase.

    Na koniec zanotuj nowy identyfikator usługi, który będzie Ci potrzebny w następnej sekcji.

  2. Utwórz klucz prywatny Apple do logowania się. W następnej sekcji będziesz potrzebować nowego klucza prywatnego i identyfikatora klucza.
  3. Jeśli używasz którejkolwiek z funkcji Uwierzytelniania Firebase, które wysyłają e-maile do użytkowników, w tym logowania za pomocą linku, potwierdzania adresu e-mail, odwoływania zmiany na koncie itp., skonfiguruj usługę przekaźnika prywatnej poczty e-mail Apple i zarejestruj noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (lub niestandardową domenę szablonu e-mail), aby firma Apple mogła przekazywać e-maile wysyłane przez Uwierzytelnianie Firebase na zanonimizowane adresy e-mail Apple.

Włącz Apple jako dostawcę logowania

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

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

Funkcja Zaloguj się przez Apple umożliwia użytkownikom anonimizację danych, w tym adresów e-mail, podczas logowania. Użytkownicy, którzy wybiorą tę opcję, mają adresy e-mail w domenie privaterelay.appleid.com. Gdy w swojej aplikacji korzystasz z funkcji Zaloguj się przez Apple, musisz przestrzegać wszystkich obowiązujących zasad dla deweloperów i warunków Apple w odniesieniu do tych zanonimizowanych identyfikatorów Apple ID.

Obejmuje to m.in. uzyskanie wymaganej zgody użytkownika przed powiązaniem jakichkolwiek danych osobowych umożliwiających bezpośrednią identyfikację z anonimowym identyfikatorem Apple ID. Podczas korzystania z Uwierzytelniania Firebase mogą to być takie działania jak:

  • Połącz adres e-mail ze zanonimizowanym identyfikatorem Apple ID lub odwrotnie.
  • Łączenie numeru telefonu ze zanonimizowanym identyfikatorem Apple ID i odwrotnie
  • Połącz nieanonimowe dane logowania społecznościowe (Facebook, Google itp.) z anonimowym identyfikatorem Apple ID lub odwrotnie.

Powyższa lista nie jest wyczerpująca. Zapoznaj się z umową licencyjną w programie Apple dla deweloperów w sekcji Wspieranie na koncie dewelopera, aby upewnić się, że aplikacja spełnia wymagania Apple.

Obsługa procesu logowania za pomocą pakietu SDK Firebase

Na Androidzie najprostszym sposobem uwierzytelnienia użytkowników w Firebase za pomocą ich kont Apple jest przeprowadzenie całego procesu logowania za pomocą pakietu SDK Firebase na Androida.

Aby obsługiwać proces logowania za pomocą pakietu SDK Firebase na Androida, wykonaj te czynności:

  1. Utwórz instancję OAuthProvider za pomocą jej konstruktora o identyfikatorze dostawcy apple.com:

    Kotlin+KTX

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

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    
  2. Opcjonalnie: określ dodatkowe zakresy OAuth 2.0 wykraczające poza domyślne, o które chcesz poprosić dostawcę uwierzytelniania.

    Kotlin+KTX

    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 każdy adres e-mail, Firebase prosi o zakresy adresów e-mail i nazw. Jeśli zmienisz to ustawienie na Wiele kont na adres e-mail, Firebase nie będzie żądać do Apple żadnych zakresów, chyba że je określisz.

  3. Opcjonalnie: jeśli chcesz wyświetlać ekran logowania Apple w języku innym niż angielski, ustaw parametr locale. Informacje o obsługiwanych językach znajdziesz w dokumentacji logowania się przez Apple.

    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");
    
  4. Uwierzytelnij w Firebase za pomocą obiektu dostawcy OAuth. Pamiętaj, że w przeciwieństwie do innych operacji FirebaseAuth ta metoda przejmie kontrolę nad interfejsem przez otwarcie niestandardowej karty Chrome. Dlatego nie wspominaj o swojej aktywności w dołączonych dokumentach OnSuccessListener i OnFailureListener, ponieważ zostaną one odłączone natychmiast po uruchomieniu interfejsu użytkownika.

    Najpierw sprawdź, czy nie masz już odpowiedzi. Jeśli zalogujesz się tą metodą, Twoja aktywność zostanie uruchomiona w tle, co oznacza, że system może ją odzyskać. Aby mieć pewność, że w takiej sytuacji użytkownik nie spróbuje ponownie, sprawdź, czy wynik już się pojawił.

    Aby sprawdzić, czy jest jakiś oczekujący wynik, wywołaj 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");
    }
    

    Jeśli nie ma oczekujących wyników, rozpocznij proces logowania, wywołując 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);
                        }
                    });
    

    W odróżnieniu od innych dostawców obsługiwanych przez Uwierzytelnianie Firebase Apple nie udostępnia adresu URL zdjęcia.

    Poza tym, gdy użytkownik nie zdecyduje się na udostępnienie aplikacji aplikacji, Apple udostępni mu unikalny adres e-mail (w formie [email protected]), który zostanie udostępniony aplikacji. Jeśli masz skonfigurowaną usługę prywatnego przekazywania poczty e-mail, Apple będzie przekazywać e-maile wysyłane na zanonimizowany adres na rzeczywisty adres e-mail użytkownika.

    Apple udostępnia aplikacjom informacje o użytkowniku, takie jak wyświetlana nazwa, wyłącznie przy pierwszym logowaniu użytkownika. Zwykle Firebase przechowuje wyświetlaną nazwę, gdy użytkownik po raz pierwszy loguje się w Apple, i można ją uzyskać za pomocą getCurrentUser().getDisplayName(). Jeśli jednak użytkownik logował się wcześniej do aplikacji bez użycia Firebase, Apple nie poda Firebase jego wyświetlanej nazwy.

Ponowne uwierzytelnianie i łączenie kont

Tego samego wzorca można używać z startActivityForReauthenticateWithProvider() i za jego pomocą pobierać nowe dane uwierzytelniające w przypadku operacji wymagających niedawnego logowania:

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.
          }
        });

Możesz też używać linkWithCredential() do łączenia różnych dostawców tożsamości z istniejącymi kontami.

Pamiętaj, że 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 na Facebooku z bieżącym kontem Firebase, użyj tokena dostępu otrzymanego podczas logowania użytkownika na Facebooku:

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.
        }
      }
    });

Zaawansowane: ręczna obsługa procesu logowania

Możesz też uwierzytelniać się w Firebase za pomocą konta Apple, przełączając proces logowania za pomocą pakietu SDK Apple Sign-In JS, ręcznie tworząc proces OAuth lub przy użyciu biblioteki OAuth takiej jak AppAuth.

  1. Dla każdego żądania logowania wygeneruj losowy ciąg znaków (jednorazową), którego będziesz używać, aby mieć pewność, że otrzymany token identyfikatora został przyznany w odpowiedzi na żądanie uwierzytelnienia aplikacji. To ważne, ponieważ zapobiega atakom metodą powtórzenia.

    Na urządzeniu z Androidem możesz wygenerować kryptograficznie bezpieczną liczbę jednorazową za pomocą SecureRandom, jak w tym przykładzie:

    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();
    }
    

    Następnie pobierz hasz SHA246 liczby jednorazowej w postaci ciągu szesnastkowego:

    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();
    }
    

    Wraz z żądaniem logowania przesyłasz identyfikator SHA256 identyfikatora jednorazowego, który Apple przekaże w odpowiedzi bez zmian. Firebase weryfikuje odpowiedź, szyfrując oryginalną liczbę jednorazową i porównując ją z wartością przekazaną przez Apple.

  2. Rozpocznij proces logowania się w Apple, korzystając z biblioteki OAuth lub innej metody. Pamiętaj, aby w żądaniu umieścić zaszyfrowany identyfikator jednorazowy jako parametr.

  3. Po otrzymaniu odpowiedzi Apple pobierz z odpowiedzi token identyfikatora i użyj go oraz niezaszyfrowanej liczby jednorazowej do utworzenia AuthCredential:

    Kotlin+KTX

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

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    
  4. Uwierzytelnij w Firebase za pomocą danych logowania do 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.
              // ...
            }
          }
        });
    

Jeśli wywołanie funkcji signInWithCredential się powiedzie, możesz pobrać dane konta użytkownika za pomocą metody getCurrentUser.

Unieważnienie tokena

Apple wymaga, aby aplikacje obsługujące tworzenie konta mogły umożliwiać użytkownikom zainicjowanie usuwania konta z poziomu aplikacji zgodnie z wytycznymi dotyczącymi sprawdzania aplikacji w App Store.

Oprócz tego aplikacje, które obsługują funkcję Zaloguj się przez Apple, powinny unieważniać tokeny użytkowników za pomocą interfejsu Zaloguj się przez Apple REST API.

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

  1. Użyj metody startActivityForSignInWithProvider(), aby zalogować się za pomocą konta Apple i uzyskać AuthResult.

  2. Uzyskaj token dostępu dla dostawcy Apple.

    Kotlin+KTX

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

    Java

    OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential();
    String accessToken = oauthCredential.getAccessToken();
    
  3. Unieważnij token za pomocą interfejsu revokeAccessToken API.

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

    Dalsze kroki

    Gdy użytkownik zaloguje się po raz pierwszy, zostaje utworzone nowe konto użytkownika powiązane z danymi logowania (tj. nazwą użytkownika i hasłem, numerem telefonu lub informacjami o dostawcy uwierzytelniania), przy użyciu którego się zalogował. Nowe konto jest przechowywane w ramach projektu Firebase i może służyć do identyfikowania użytkowników we wszystkich aplikacjach w projekcie niezależnie od tego, jak się on zaloguje.

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

    • W Regułach zabezpieczeń Bazy danych czasu rzeczywistego Firebase i Cloud Storage możesz uzyskać unikalny identyfikator zalogowanego użytkownika ze zmiennej auth i za jego pomocą kontrolować, do jakich danych ma on dostęp.

    Jeśli chcesz zezwolić użytkownikom na logowanie się w Twojej aplikacji za pomocą różnych dostawców uwierzytelniania, możesz połączyć dane logowania dostawcy uwierzytelniania z istniejącym kontem użytkownika.

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

    Kotlin+KTX

    Firebase.auth.signOut()

    Java

    FirebaseAuth.getInstance().signOut();