Google is committed to advancing racial equity for Black communities. See how.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Autenticare con Apple su iOS

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

Prima di iniziare

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

Unisciti al programma per sviluppatori Apple

Accedi con Apple può essere configurato solo dai membri del Programma per gli sviluppatori Apple .

Configura Accedi con Apple

  1. Abilita Accedi con Apple per la tua app nella pagina Certificati, identificatori e profili del sito per sviluppatori di Apple.
  2. Se si utilizza una delle funzionalità di Firebase Authentication che inviano e-mail agli utenti, tra cui l'accesso al collegamento e-mail, la verifica dell'indirizzo e-mail, la revoca della modifica dell'account e altri, configurare il servizio di inoltro e -mail privato Apple e registrare noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (o il dominio del modello di posta elettronica personalizzato) in modo che Apple possa inoltrare le e-mail inviate da Firebase Authentication a indirizzi e-mail Apple anonimi.

Abilita Apple come provider di accesso

  1. Aggiungi Firebase al tuo progetto iOS . Assicurati di registrare l'ID bundle dell'app quando configuri l'app nella console di Firebase.
  2. Nella console di Firebase , apri la sezione Auth . Nella scheda Metodo di accesso , abilitare il provider Apple . Se stai utilizzando Accedi solo con Apple in un'app iOS, puoi lasciare vuoti i campi ID servizio, ID team Apple, chiave privata e ID chiave.

Rispettare i requisiti dei dati anonimi di Apple

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

Ciò include l'ottenimento del consenso dell'utente richiesto prima di associare qualsiasi informazione personale che identifichi direttamente 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 sociale non anonima (Facebook, Google, ecc.) A un ID Apple anonimo o viceversa.

L'elenco sopra non è esaustivo. Fai riferimento all'Accordo di licenza del programma per sviluppatori Apple nella sezione Iscrizione del tuo account sviluppatore per assicurarti che l'app soddisfi i requisiti di Apple.

Accedi con Apple e esegui l'autenticazione con Firebase

Per eseguire l'autenticazione con un account Apple, accedi prima all'account Apple utilizzando il framework AuthenticationServices di Apple, quindi utilizza il token ID dalla risposta di Apple per creare un oggetto Firebase AuthCredential :

  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 tipo replay.

    È possibile generare un nonce crittograficamente sicuro su iOS con SecRandomCopyBytes(_:_:_) , come nell'esempio seguente:

    veloce

     // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      let charset: Array<Character> =
          Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
      var result = ""
      var remainingLength = length
    
      while remainingLength > 0 {
        let randoms: [UInt8] = (0 ..< 16).map { _ in
          var random: UInt8 = 0
          let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
          if errorCode != errSecSuccess {
            fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
          }
          return random
        }
    
        randoms.forEach { random in
          if remainingLength == 0 {
            return
          }
    
          if random < charset.count {
            result.append(charset[Int(random)])
            remainingLength -= 1
          }
        }
      }
    
      return result
    }
     

    Objective-C

     - (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--;
          }
        }
      }
    
      return result;
    }
     

    Invierai l'hash SHA256 del nonce con la tua richiesta di accesso, che Apple passerà invariata 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, incluso nella tua richiesta l'hash SHA256 del nonce e la classe delegata che gestirà la risposta di Apple (vedi il passaggio successivo):

    veloce

     import CryptoKit
    
    // Unhashed nonce.
    fileprivate var currentNonce: String?
    
    @available(iOS 13, *)
    func startSignInWithAppleFlow() {
      let nonce = randomNonceString()
      currentNonce = nonce
      let appleIDProvider = ASAuthorizationAppleIDProvider()
      let request = appleIDProvider.createRequest()
      request.requestedScopes = [.fullName, .email]
      request.nonce = sha256(nonce)
    
      let authorizationController = ASAuthorizationController(authorizationRequests: [request])
      authorizationController.delegate = self
      authorizationController.presentationContextProvider = self
      authorizationController.performRequests()
    }
    
    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        return String(format: "%02x", $0)
      }.joined()
    
      return hashString
    }
     

    Objective-C

     @import CommonCrypto;
    
    - (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. ASAuthorizationControllerDelegate la risposta di Apple nell'implementazione di ASAuthorizationControllerDelegate . Se l'accesso ha esito positivo, utilizzare il token ID dalla risposta di Apple con il nonce non cancellato per eseguire l'autenticazione con Firebase:

    veloce

     @available(iOS 13.0, *)
    extension MainViewController: ASAuthorizationControllerDelegate {
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
          guard let nonce = currentNonce else {
            fatalError("Invalid state: A login callback was received, but no login request was sent.")
          }
          guard let appleIDToken = appleIDCredential.identityToken else {
            print("Unable to fetch identity token")
            return
          }
          guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
            return
          }
          // Initialize a Firebase credential.
          let credential = OAuthProvider.credential(withProviderID: "apple.com",
                                                    IDToken: idTokenString,
                                                    rawNonce: nonce)
          // Sign in with Firebase.
          Auth.auth().signIn(with: credential) { (authResult, error) in
            if error {
              // Error. If error.code == .MissingOrInvalidNonce, make sure
              // you're sending the SHA256-hashed nonce as a hex string with
              // your request to Apple.
              print(error.localizedDescription)
              return
            }
            // User is signed in to Firebase with Apple.
            // ...
          }
        }
      }
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        print("Sign in with Apple errored: \(error)")
      }
    
    }
     

    Objective-C

     - (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);
        }
    
        // Initialize a Firebase credential.
        FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com"
                                                                            IDToken:idToken
                                                                           rawNonce:rawNonce];
    
        // Sign in with Firebase.
        [[FIRAuth auth] signInWithCredential:credential
                                  completion:^(FIRAuthDataResult * _Nullable authResult,
                                               NSError * _Nullable error) {
          if (error != nil) {
            // Error. If error.code == FIRAuthErrorCodeMissingOrInvalidNonce,
            // make sure you're sending the SHA256-hashed nonce as a hex string
            // with your request to Apple.
            return;
          }
          // Sign-in succeeded!
        }];
      }
    }
    
    - (void)authorizationController:(ASAuthorizationController *)controller
               didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
      NSLog(@"Sign in with Apple errored: %@", error);
    }
     

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

Inoltre, quando l'utente sceglie di non condividere la propria e-mail con l'app, Apple xyz@privaterelay.appleid.com 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 al reale indirizzo e-mail dell'utente.

Apple condivide le informazioni dell'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 Auth.auth().currentUser.displayName con Apple, che è possibile ottenere con Auth.auth().currentUser.displayName . Tuttavia, se in precedenza hai utilizzato Apple per accedere a 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 reauthenticateWithCredential() , che è possibile utilizzare per recuperare una nuova credenziale per le operazioni sensibili che richiedono l'accesso recente:

veloce

 // Initialize a fresh Apple credential with Firebase.
let credential = OAuthProvider.credential(
  withProviderID: "apple.com",
  IDToken: appleIdToken,
  rawNonce: rawNonce
)
// Reauthenticate current Apple user with fresh Apple credential.
Auth.auth().currentUser.reauthenticate(with: credential) { (authResult, error) in
  guard error != nil else { return }
  // Apple user successfully re-authenticated.
  // ...
}
 

Objective-C

 FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com",
                                                                   IDToken:appleIdToken,
                                                                  rawNonce:rawNonce];
[[FIRAuth auth].currentUser
    reauthenticateWithCredential:credential
                      completion:^(FIRAuthDataResult * _Nullable authResult,
                                   NSError * _Nullable error) {
  if (error) {
    // Handle error.
  }
  // Apple user successfully re-authenticated.
  // ...
}];
 

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

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

Accedi con Apple non ti consentirà di riutilizzare una credenziale di autenticazione per collegarti a un account esistente. Se desideri collegare un accesso con le credenziali di Apple a un altro account, devi prima provare a collegare gli account utilizzando il vecchio accesso con le credenziali di Apple e quindi esaminare l'errore restituito per trovare una nuova credenziale. La nuova credenziale sarà situato nella dell'errore userInfo dizionario e si può accedere tramite il FIRAuthErrorUserInfoUpdatedCredentialKey chiave.

Ad esempio, per collegare un account Facebook all'attuale account Firebase, utilizzare il token di accesso ottenuto dall'accesso dell'utente a Facebook:

veloce

 // Initialize a Facebook credential with Firebase.
let credential = FacebookAuthProvider.credential(
  withAccessToken: AccessToken.current!.tokenString
)
// Assuming the current user is an Apple user linking a Facebook provider.
Auth.auth().currentUser.link(with: credential) { (authResult, error) in
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}
 

Objective-C

 // Initialize a Facebook credential with Firebase.
FacebookAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken];
// Assuming the current user is an Apple user linking a Facebook provider.
[FIRAuth.auth linkWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}];
 

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 del provider di autenticazione, con cui l'utente ha effettuato l'accesso. Questo nuovo account viene archiviato come parte del progetto Firebase e può essere utilizzato per identificare un utente in ogni app del progetto, indipendentemente da come l'utente accede.

  • Nelle tue app puoi ottenere le informazioni di base sul profilo FIRUser dall'oggetto FIRUser . Vedi Gestisci utenti .

  • Nelle regole di sicurezza di Firebase Realtime Database e Cloud Storage, è possibile ottenere l'ID utente univoco dell'utente connesso dalla variabile auth e utilizzarlo per controllare i dati a cui un utente può accedere.

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, chiamare signOut:

veloce

    let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print ("Error signing out: %@", signOutError)
}
  

Objective-C

    NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

È inoltre possibile aggiungere un codice di gestione degli errori per l'intera gamma di errori di autenticazione. Vedi Gestisci errori .