Autenticati utilizzando Apple e C++

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

Prima di iniziare

Per accedere agli utenti utilizzando Apple, configura prima Accedi con Apple sul sito degli sviluppatori Apple, quindi abilita Apple come provider di accesso per il tuo progetto Firebase.

Unisciti all'Apple Developer Program

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

Configura Accedi con Apple

L'accesso a Apple deve essere abilitato e configurato correttamente nel tuo progetto Firebase. La configurazione varia tra le piattaforme Android e Apple. Segui la sezione "Configura Accedi con Apple" delle piattaforme Apple e/o delle guide Android prima di procedere.

Abilita Apple come provider di accesso

  1. Nella console Firebase , apri la sezione Auth . Nella scheda Metodo di accesso, abilita il provider Apple .
  2. Configura le impostazioni del provider di accesso Apple:
    1. Se stai distribuendo la tua app solo su piattaforme Apple, puoi lasciare vuoti i campi ID servizio, ID team Apple, chiave privata e ID chiave.
    2. Per il supporto sui dispositivi Android:
      1. Aggiungi Firebase al tuo progetto Android . Assicurati di registrare la firma SHA-1 della tua app quando configuri l'app nella console Firebase.
      2. Nella console Firebase , apri la sezione Auth . Nella scheda Metodo di accesso, abilita il provider Apple . Specifica l'ID servizio che hai creato nella sezione precedente. Inoltre, nella sezione di configurazione del flusso di codice OAuth, specifica il tuo ID Apple Team 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 il proprio 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 degli sviluppatori di Apple in merito a questi ID Apple anonimizzati.

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

  • Collega un indirizzo e-mail a un ID Apple anonimo 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 anonimo o viceversa.

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

Accedi alla 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 classe firebase::App .
    #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 firebase::auth::Auth per la tua 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 Firebase SDK

La procedura per accedere con Apple varia tra le piattaforme Apple e Android.

Su piattaforme Apple

Autentica i tuoi utenti con Firebase tramite l'accesso Apple SDK Objective-C richiamato dal tuo 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 attacchi di riproduzione.

      - (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 tua richiesta di accesso, che Apple passerà invariato 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 tua 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 nella tua implementazione di ASAuthorizationControllerDelegate`. Se l'accesso ha avuto esito positivo, utilizza il token ID dalla risposta di Apple con il nonce senza hash 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. Usa la stringa di token risultante e l'originale nonce 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::User*> result =
        auth->SignInWithCredential(credential);
    
  5. Lo stesso modello può essere utilizzato con Reauthenticate , che può essere utilizzato per recuperare nuove credenziali per operazioni sensibili che richiedono un accesso recente.

    firebase::Future<firebase::auth::SignInResult> result =
        user->Reauthenticate(credential);
    
  6. Lo stesso schema può essere utilizzato per collegare un account con Apple Sign In. Tuttavia, potresti riscontrare un errore quando un account Firebase esistente è già stato collegato all'account Apple a cui stai tentando di collegarti. Quando ciò si verifica, il futuro restituirà uno stato di kAuthErrorCredentialAlreadyInUse e l'oggetto UserInfo di SignInResult potrebbe contenere un updated_credential valido. Questa credenziale può essere utilizzata per accedere all'account collegato ad Apple tramite SignInWithCredential senza la necessità di generare un altro token di accesso Apple e nonce.

    Si noti che è necessario utilizzare LinkAndRetrieveDataWithCredential affinché questa operazione contenga la credenziale poiché updated_credential è un membro dell'oggetto SignInResult.UserInfo .

    firebase::Future<firebase::auth::SignInResult> link_result =
        auth->current_user()->LinkAndRetrieveDataWithCredential(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()->info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::User*> result = auth->SignInWithCredential(
          link_result.result()->info.updated_credential);
    } else {
      // Another link error occurred.
    }
    

Su Android

Su Android, autentica i tuoi utenti con Firebase integrando il login OAuth generico basato sul Web nella tua app utilizzando Firebase SDK per eseguire il flusso di accesso end-to-end.

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

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

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. Facoltativo: specificare ulteriori ambiti OAuth 2.0 oltre a quello predefinito che si desidera richiedere al provider di autenticazione.

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  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 localizzazioni supportate.

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

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. Autenticarsi con Firebase utilizzando l'oggetto provider Auth. Tieni presente che, a differenza di altre operazioni FirebaseAuth, questo prenderà il controllo della tua interfaccia utente aprendo una vista Web in cui l'utente può inserire le proprie credenziali.

    Per avviare il flusso di accesso, chiama signInWithProvider :

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

    L'applicazione potrebbe quindi attendere o registrare una richiamata su Future .

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

    firebase::Future<firebase::auth::SignInResult> result =
      user->ReauthenticateWithProvider(provider_data);
    

    L'applicazione potrebbe quindi attendere o registrare una richiamata su Future .

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

    Tieni presente che Apple richiede 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::SignInResult> result =
        auth.getCurrentUser().linkWithCredential(credential);
    

Accedi con Apple Notes

A differenza di altri provider supportati da Firebase Auth, Apple non fornisce un URL per la 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 (del 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 accedere all'app senza utilizzare Firebase, Apple non fornirà a Firebase il nome visualizzato dell'utente.

Prossimi passi

Dopo che un utente accede per la prima volta, un nuovo account utente viene creato e collegato alle credenziali, ovvero il nome utente e la password, il numero di telefono o le 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 da come l'utente effettua l'accesso.

Nelle tue app, puoi ottenere le informazioni del profilo di base dell'utente dall'oggetto firebase::auth::user. Vedere Gestisci utenti .

Nelle regole di sicurezza del database in tempo reale e dell'archiviazione cloud di Firebase, 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.