Autenticarsi utilizzando Apple su Android

Puoi consentire ai tuoi utenti di eseguire l'autenticazione con Firebase utilizzando il loro ID Apple utilizzando l'SDK Firebase per eseguire il flusso di accesso OAuth 2.0 end-to-end.

Prima di iniziare

Per eseguire l'accesso degli utenti utilizzando Apple, configurare innanzitutto Accedi con Apple sul sito per sviluppatori di Apple, quindi abilitare Apple come provider di accesso per il progetto Firebase.

Partecipa all'Apple Developer Program

Accedi con Apple può essere configurato solo dai membri dell'Apple Developer Program .

Configura Accedi con Apple

Sul sito Apple Developer , procedi come segue:

  1. Associa il tuo sito Web alla tua app come descritto nella prima sezione di Configura l'accesso con Apple per il Web . Quando richiesto, registra il seguente URL come URL di ritorno:

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

    Puoi ottenere il tuo ID progetto Firebase nella pagina delle impostazioni della console Firebase .

    Quando hai finito, prendi nota del tuo nuovo ID servizio, che ti servirà nella sezione successiva.

  2. Crea una chiave privata Accedi con Apple . Avrai bisogno della tua nuova chiave privata e ID chiave nella sezione successiva.
  3. Se utilizzi una delle funzionalità di Firebase Authentication che inviano email agli utenti, tra cui l'accesso al collegamento email, la verifica dell'indirizzo email, la revoca della modifica dell'account e altro, configura il servizio di inoltro email privato di Apple e registra noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (o il dominio del tuo modello di email personalizzato) in modo che Apple possa inoltrare le email inviate da Firebase Authentication a indirizzi email Apple anonimi.

Abilita Apple come provider di accesso

  1. Aggiungi Firebase al tuo progetto Android . Assicurati di registrare la firma SHA-1 della tua app quando configuri la tua app nella console Firebase.
  2. Nella console Firebase , apri la sezione Auth . Nella scheda Metodo di accesso abilitare il provider Apple . Specifica l'ID servizio che hai creato nella sezione precedente. Inoltre, nella sezione Configurazione del flusso di codice OAuth , specifica il tuo ID team Apple e la chiave privata e l'ID chiave che hai creato nella sezione precedente.

Rispetta i requisiti dei dati anonimi di Apple

Accedi con Apple offre agli utenti la possibilità di rendere anonimi i propri dati, incluso l'indirizzo e-mail, al momento dell'accesso. Gli utenti che scelgono questa opzione hanno indirizzi e-mail con il dominio privaterelay.appleid.com . Quando utilizzi Accedi con Apple nella tua app, devi rispettare tutte le politiche o i termini applicabili per gli sviluppatori di Apple in merito a questi ID Apple anonimizzati.

Ciò include l'ottenimento di qualsiasi consenso dell'utente richiesto prima di associare qualsiasi informazione personale di identificazione diretta con un ID Apple anonimizzato. Quando si utilizza l'autenticazione Firebase, ciò può includere le seguenti azioni:

  • Collega un indirizzo e-mail a un ID Apple anonimizzato o viceversa.
  • Collega un numero di telefono a un ID Apple anonimo o viceversa
  • Collega una credenziale social non anonima (Facebook, Google, ecc.) a un ID Apple anonimizzato o viceversa.

L'elenco di cui sopra non è esaustivo. Fai riferimento al Contratto di licenza dell'Apple Developer Program nella sezione Iscrizione del tuo account sviluppatore per assicurarti che la tua app soddisfi i requisiti di Apple.

Gestisci il flusso di accesso con l'SDK Firebase

Su Android, il modo più semplice per autenticare gli utenti con Firebase utilizzando i loro account Apple è gestire l'intero flusso di accesso con Firebase Android SDK.

Per gestire il flusso di accesso con Firebase Android SDK, procedi nel seguente modo:

  1. Costruisci un'istanza di un OAuthProvider utilizzando il suo Builder con l'ID provider apple.com :

    Kotlin+KTX

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

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    
  2. Facoltativo: specificare ulteriori ambiti OAuth 2.0 oltre a quello predefinito che si desidera richiedere al provider di autenticazione.

    Kotlin+KTX

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

    Java

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

    Per impostazione predefinita, quando è abilitato Un account per indirizzo email , Firebase richiede gli ambiti email e nome. Se modifichi questa impostazione in Più account per indirizzo email , Firebase non richiede alcun ambito da Apple a meno che tu non lo specifichi.

  3. Facoltativo: se desideri visualizzare la schermata di accesso di Apple in una lingua diversa dall'inglese, imposta il parametro locale . Consulta i documenti Accedi con Apple per le impostazioni locali supportate.

    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. Esegui l'autenticazione con Firebase utilizzando l'oggetto provider OAuth. Tieni presente che, a differenza di altre operazioni FirebaseAuth , questo prenderà il controllo della tua interfaccia utente aprendo una scheda Chrome personalizzata. Di conseguenza, non fare riferimento alla tua attività in OnSuccessListener e OnFailureListener che alleghi poiché si scollegheranno immediatamente quando l'operazione avvia l'interfaccia utente.

    Dovresti prima controllare se hai già ricevuto una risposta. L'accesso con questo metodo mette la tua attività in background, il che significa che può essere recuperata dal sistema durante il flusso di accesso. Per assicurarti di non costringere l'utente a riprovare se ciò accade, dovresti controllare se è già presente un risultato.

    Per verificare se c'è un risultato in sospeso, chiama 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");
    }
    

    Se non ci sono risultati in sospeso, avvia il flusso di accesso chiamando 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);
                        }
                    });
    

    A differenza di altri provider supportati da Firebase Auth, Apple non fornisce un URL della foto.

    Inoltre, quando l'utente sceglie di non condividere la propria e-mail con l'app, Apple fornisce un indirizzo e-mail univoco per quell'utente (nel formato xyz@privaterelay.appleid.com ), che condivide con la tua app. Se hai configurato il servizio di inoltro e-mail privato, Apple inoltra le e-mail inviate all'indirizzo anonimo all'indirizzo e-mail reale dell'utente.

    Apple condivide solo le informazioni utente come il nome visualizzato con le app la prima volta che un utente accede. Di solito, Firebase memorizza il nome visualizzato la prima volta che un utente accede con Apple, che puoi ottenere con getCurrentUser().getDisplayName() . Tuttavia, se in precedenza hai utilizzato Apple per far accedere un utente all'app senza utilizzare Firebase, Apple non fornirà a Firebase il nome visualizzato dell'utente.

Riautenticazione e collegamento dell'account

Lo stesso modello può essere utilizzato con startActivityForReauthenticateWithProvider() che puoi utilizzare per recuperare una nuova credenziale per operazioni sensibili che richiedono un accesso recente:

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

Inoltre, puoi utilizzare linkWithCredential() per collegare diversi provider di identità agli account esistenti.

Tieni presente che Apple richiede di ottenere il consenso esplicito degli utenti prima di collegare i loro account Apple ad altri dati.

Ad esempio, per collegare un account Facebook all'account Firebase corrente, utilizza il token di accesso ottenuto dall'accesso dell'utente a 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.
        }
      }
    });

Avanzate: gestisci il flusso di accesso manualmente

Puoi anche eseguire l'autenticazione con Firebase utilizzando un account Apple gestendo il flusso di accesso utilizzando l'SDK JS di Apple Sign-In, creando manualmente il flusso OAuth o utilizzando una libreria OAuth come AppAuth .

  1. Per ogni richiesta di accesso, genera una stringa casuale, un "nonce", che utilizzerai per assicurarti che il token ID che ottieni sia stato concesso specificamente in risposta alla richiesta di autenticazione della tua app. Questo passaggio è importante per prevenire gli attacchi di riproduzione.

    Puoi generare un nonce crittograficamente sicuro su Android con SecureRandom , come nell'esempio seguente:

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

    Quindi, ottieni l'hash SHA246 del nonce come stringa esadecimale:

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

    Invierai l'hash SHA256 del nonce con la tua richiesta di accesso, che Apple passerà senza modifiche nella risposta. Firebase convalida la risposta eseguendo l'hashing del nonce originale e confrontandolo con il valore trasmesso da Apple.

  2. Avvia il flusso di accesso di Apple utilizzando la tua libreria OAuth o un altro metodo. Assicurati di includere il nonce con hash come parametro nella tua richiesta.

  3. Dopo aver ricevuto la risposta di Apple, ottieni il token ID dalla risposta e usalo insieme al nonce senza hash per creare un 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. Esegui l'autenticazione con Firebase utilizzando le credenziali 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.
              // ...
            }
          }
        });
    

Se la chiamata a signInWithCredential positivo, puoi utilizzare il metodo getCurrentUser per ottenere i dati dell'account dell'utente.

Prossimi passi

Dopo che un utente ha effettuato l'accesso per la prima volta, viene creato un nuovo account utente e collegato alle credenziali, ovvero nome utente e password, numero di telefono o informazioni sul provider di autenticazione, con cui l'utente ha effettuato l'accesso. Questo nuovo account viene archiviato come parte del tuo progetto Firebase e può essere utilizzato per identificare un utente in ogni app del tuo progetto, indipendentemente dalla modalità di accesso dell'utente.

  • Nelle tue app puoi ottenere le informazioni di base sul profilo dell'utente dall'oggetto FirebaseUser . Vedere Gestire gli utenti .

  • In Firebase Realtime Database and Cloud Storage Security Rules , puoi ottenere l'ID utente univoco dell'utente che ha eseguito l'accesso dalla variabile auth e utilizzarlo per controllare a quali dati può accedere un utente.

Puoi consentire agli utenti di accedere alla tua app utilizzando più provider di autenticazione collegando le credenziali del provider di autenticazione a un account utente esistente.

Per disconnettere un utente, chiama signOut :

Kotlin+KTX

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();