Esegui l'autenticazione con Apple e C++

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

Prima di iniziare

Per consentire agli utenti di accedere utilizzando Apple, configura prima Sign in with Apple sul sito per sviluppatori di Apple, poi attiva Apple come provider di accesso per il tuo progetto Firebase.

Partecipa all'Apple Developer Program

Sign in with Apple può essere configurato solo dai membri dell'Apple Developer Program.

Configura Sign in with Apple

Sign in with Apple deve essere attivato e configurato correttamente nel tuo progetto Firebase. La configurazione varia a seconda delle piattaforme Android e Apple. Prima di procedere, segui la sezione "Configura Sign in with Apple" delle guide per le piattaforme Apple e/o Android.

Attiva Apple come provider di accesso

  1. Nella console Firebase, vai a Sicurezza > Autenticazione.
  2. Nella scheda Metodo di accesso, attiva il provider di accesso Apple.
  3. Configura le impostazioni del provider di accesso Apple:
    • Apple: se esegui il deployment della tua app solo sulle piattaforme Apple, puoi lasciare vuoti i campi ID servizio, ID team Apple, chiave privata e ID chiave.
    • Android: completa i seguenti passaggi per supportare i dispositivi Android:
      1. Aggiungi Firebase al tuo progetto Android.
      2. Specifica l'impronta SHA-1 della tua app, se non l'hai già fatto.
        1. Nella console Firebase, vai alla scheda Impostazioni > Generali.
        2. Scorri verso il basso fino alla scheda Le tue app , seleziona la tua app per Android e aggiungi l'impronta SHA-1 nel campo Impronte dei certificati SHA.

        Per informazioni dettagliate su come ottenere l'impronta SHA della tua app, consulta Autenticare il client.

      3. Configura le impostazioni del provider di accesso Apple:
        1. Nella console Firebase, vai a Sicurezza > Autenticazione.
        2. Nella scheda Metodo di accesso, fai clic sul provider di accesso Apple.
        3. Specifica l'ID servizio che hai creato nella sezione precedente. Inoltre, nella sezione di configurazione del flusso di codice OAuth, specifica l'ID team Apple, la chiave privata e l'ID chiave che hai creato nella sezione precedente.

Rispetta i requisiti di Apple per i dati anonimizzati

Sign in with Apple offre agli utenti la possibilità di anonimizzare i propri dati, incluso l'indirizzo email, durante l'accesso. Gli utenti che scelgono questa opzione hanno indirizzi email con il dominio privaterelay.appleid.com. Quando utilizzi Sign in with Apple nella tua app, devi rispettare le norme o i termini per gli sviluppatori applicabili di Apple relativi a questi ID Apple anonimizzati.

Ciò include l'ottenimento di qualsiasi consenso dell'utente richiesto prima di associare informazioni personali che identificano direttamente l'utente a un ID Apple anonimizzato. Quando utilizzi Firebase Authentication, potresti dover eseguire le seguenti azioni:

  • Collegare un indirizzo email a un ID Apple anonimizzato o viceversa.
  • Collegare un numero di telefono a un ID Apple anonimizzato o viceversa.
  • Collegare una credenziale social non anonima (Facebook, Google e così via) a un ID Apple anonimizzato o viceversa.

L'elenco sopra riportato non è esaustivo. Per assicurarti che la tua app soddisfi i requisiti di Apple, consulta il Contratto di licenza del programma per sviluppatori Apple nella sezione Abbonamento del tuo account sviluppatore.

Accedi alla classe firebase::auth::Auth

La classe Auth è il gateway per tutte le chiamate API.
  1. Aggiungi i file di intestazione Auth e App:
    #include "firebase/app.h"
    #include "firebase/auth.h"
  2. Nel codice di inizializzazione, crea una firebase::App classe.
    #if defined(__ANDROID__)
      firebase::App* app =
          firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity);
    #else
      firebase::App* app = firebase::App::Create(firebase::AppOptions());
    #endif  // defined(__ANDROID__)
  3. Acquisisci la classe firebase::auth::Auth per firebase::App. Esiste una mappatura uno a uno tra App e Auth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);

Gestisci il flusso di accesso con l'SDK Firebase

La procedura per accedere con Apple varia a seconda delle piattaforme Apple e Android.

Sulle piattaforme Apple

Autentica gli utenti con Firebase tramite l'SDK Objective-C di Sign in with Apple richiamato dal codice C++.

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

      - (NSString *)randomNonce:(NSInteger)length {
        NSAssert(length > 0, @"Expected nonce to have positive length");
        NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
        NSMutableString *result = [NSMutableString string];
        NSInteger remainingLength = length;
    
        while (remainingLength > 0) {
          NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16];
          for (NSInteger i = 0; i < 16; i++) {
            uint8_t random = 0;
            int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random);
            NSAssert(errorCode == errSecSuccess, @"Unable to generate nonce: OSStatus %i", errorCode);
    
            [randoms addObject:@(random)];
          }
    
          for (NSNumber *random in randoms) {
            if (remainingLength == 0) {
              break;
            }
    
            if (random.unsignedIntValue < characterSet.length) {
              unichar character = [characterSet characterAtIndex:random.unsignedIntValue];
              [result appendFormat:@"%C", character];
              remainingLength--;
            }
          }
        }
      }
    
    

    Invierai l'hash SHA256 del nonce con la 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 passato da Apple.

  2. Avvia il flusso di accesso di Apple, includendo nella richiesta l'hash SHA256 del nonce e la classe delegata che gestirà la risposta di Apple (vedi il passaggio successivo):

      - (void)startSignInWithAppleFlow {
        NSString *nonce = [self randomNonce:32];
        self.currentNonce = nonce;
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest];
        request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
        request.nonce = [self stringBySha256HashingString:nonce];
    
        ASAuthorizationController *authorizationController =
            [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
        authorizationController.delegate = self;
        authorizationController.presentationContextProvider = self;
        [authorizationController performRequests];
      }
    
      - (NSString *)stringBySha256HashingString:(NSString *)input {
        const char *string = [input UTF8String];
        unsigned char result[CC_SHA256_DIGEST_LENGTH];
        CC_SHA256(string, (CC_LONG)strlen(string), result);
    
        NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
        for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
          [hashed appendFormat:@"%02x", result[i]];
        }
        return hashed;
      }
    
  3. Gestisci la risposta di Apple nell'implementazione di ASAuthorizationControllerDelegate`. Se l'accesso è andato a buon fine, utilizza il token ID della risposta di Apple con il nonce non sottoposto a hashing per eseguire l'autenticazione con Firebase:

      - (void)authorizationController:(ASAuthorizationController *)controller
         didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
        if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
          ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
          NSString *rawNonce = self.currentNonce;
          NSAssert(rawNonce != nil, @"Invalid state: A login callback was received, but no login request was sent.");
    
          if (appleIDCredential.identityToken == nil) {
            NSLog(@"Unable to fetch identity token.");
            return;
          }
    
          NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken
                                                    encoding:NSUTF8StringEncoding];
          if (idToken == nil) {
            NSLog(@"Unable to serialize id token from data: %@", appleIDCredential.identityToken);
          }
        }
    
  4. Utilizza la stringa del token risultante e il nonce originale per creare una credenziale Firebase e accedere a Firebase.

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  5. Lo stesso pattern può essere utilizzato con Reauthenticate, che può essere utilizzato per recuperare nuove credenziali per le operazioni sensibili che richiedono un accesso recente.

    firebase::Future<firebase::auth::AuthResult> result =
        user->Reauthenticate(credential);
    
  6. Lo stesso pattern può essere utilizzato per collegare un account a Sign in with Apple. Tuttavia, potresti riscontrare un errore quando un account Firebase esistente è già stato collegato all'account Apple a cui stai tentando di collegarti. In questo caso, il futuro restituirà lo stato kAuthErrorCredentialAlreadyInUse e AuthResult potrebbe contenere una credential valida. Questa credenziale può essere utilizzata per accedere all'account collegato ad Apple tramite SignInAndRetrieveDataWithCredential senza dover generare un altro token e nonce di Sign in with Apple.

    firebase::Future<firebase::auth::AuthResult> link_result =
        auth->current_user().LinkWithCredential(credential);
    
    // To keep example simple, wait on the current thread until call completes.
    while (link_result.status() == firebase::kFutureStatusPending) {
      Wait(100);
    }
    
    // Determine the result of the link attempt
    if (link_result.error() == firebase::auth::kAuthErrorNone) {
      // user linked correctly.
    } else if (link_result.error() ==
                   firebase::auth::kAuthErrorCredentialAlreadyInUse &&
               link_result.result()
                   ->additional_user_info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::AuthResult> result =
          auth->SignInAndRetrieveDataWithCredential(
              link_result.result()->additional_user_info.updated_credential);
    } else {
      // Another link error occurred.
    }

Su Android

Su Android, autentica gli utenti con Firebase integrando l'accesso OAuth generico basato sul web nella tua app utilizzando l'SDK Firebase per eseguire il flusso di accesso end-to-end.

Per gestire il flusso di accesso con l'SDK Firebase:

  1. Crea un'istanza di FederatedOAuthProviderData configurata con l'ID provider appropriato per Apple.

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. Facoltativo:specifica ambiti OAuth 2.0 aggiuntivi oltre a quelli predefiniti che vuoi richiedere al provider di autenticazione.

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. Facoltativo:se vuoi visualizzare la schermata di accesso di Apple in una lingua diversa dall'inglese, imposta il parametro locale. Per le impostazioni locali supportate, consulta la documentazione di Sign in with Apple.

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. Una volta configurati i dati del provider, utilizzali per creare un FederatedOAuthProvider.

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. Esegui l'autenticazione con Firebase utilizzando l'oggetto provider Auth. Tieni presente che, a differenza di altre operazioni di FirebaseAuth, questa operazione prenderà il controllo dell'interfaccia utente visualizzando una visualizzazione web in cui l'utente può inserire le proprie credenziali.

    Per avviare il flusso di accesso, chiama signInWithProvider:

    firebase::Future<firebase::auth::AuthResult> result =
      auth->SignInWithProvider(provider_data);
    

    L'applicazione può quindi attendere o registrare un callback sul futuro.

  6. Lo stesso pattern può essere utilizzato con ReauthenticateWithProvider, che può essere utilizzato per recuperare nuove credenziali per le operazioni sensibili che richiedono un accesso recente.

    firebase::Future<firebase::auth::AuthResult> result =
      user.ReauthenticateWithProvider(provider_data);
    

    L'applicazione può quindi attendere o registrare un callback su il futuro.

  7. 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:

    // Initialize a Facebook credential with a Facebook access token.
    AuthCredential credential =
        firebase::auth::FacebookAuthProvider.getCredential(token);
    
    // Assuming the current user is an Apple user linking a Facebook provider.
    firebase::Future<firebase::auth::AuthResult> result =
        auth.current_user().LinkWithCredential(credential);
    

Note su Sign in with Apple

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

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

Apple condivide le informazioni utente, come il nome visualizzato, con le app solo la prima volta che un utente accede. In genere, Firebase memorizza il nome visualizzato la prima volta che un utente accede con Apple, che puoi ottenere con current_user().display_name(). Tuttavia, se in precedenza hai utilizzato Apple per consentire a un utente di accedere all'app senza utilizzare Firebase, Apple non fornirà a Firebase il nome visualizzato dell'utente.

Passaggi successivi

Dopo che un utente ha eseguito l'accesso per la prima volta, viene creato un nuovo account utente e collegato alle credenziali, ovvero al nome utente e alla password, al numero di telefono o alle informazioni del provider di autenticazione con cui l'utente ha eseguito l'accesso. Questo nuovo account viene memorizzato 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 del profilo dell'utente dall'oggetto firebase::auth::User. Consulta Gestire gli utenti.

Nelle regole di sicurezza di Firebase Realtime Database e Cloud Storage, puoi ottenere l'ID utente univoco dell'utente che ha eseguito l'accesso dalla variabile auth e utilizzarlo per controllare i dati a cui un utente può accedere.