Mit Apple authentifizieren

Sie können Ihren Nutzern die Authentifizierung mit Firebase über ihre Apple-ID ermöglichen, indem Sie das Firebase SDK verwenden, um den End-to-End-OAuth 2.0-Anmeldevorgang durchzuführen.

Hinweis

Wenn Sie Nutzer mit Apple anmelden möchten, müssen Sie zuerst „Mit Apple anmelden“ auf der Entwicklerwebsite von Apple konfigurieren und dann Apple als Anmeldeanbieter für Ihr Firebase-Projekt aktivieren.

Am Apple-Programm für Entwickler teilnehmen

„Über Apple anmelden“ kann nur von Mitgliedern des Apple-Programms für Entwickler konfiguriert werden.

Über Apple anmelden konfigurieren

  1. Aktivieren Sie die Anmeldung mit Apple für Ihre App auf der Seite Certificates, Identifiers & Profiles (Zertifikate, Kennungen und Profile) auf der Entwicklerwebsite von Apple.
  2. Verknüpfen Sie Ihre Website mit Ihrer App, wie im ersten Abschnitt von Mit Apple im Web anmelden beschrieben. Registrieren Sie die folgende URL als Return-URL, wenn Sie dazu aufgefordert werden:
    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
    Sie finden die ID Ihres Firebase-Projekts auf der Seite Firebase-Konsoleneinstellungen. Notieren Sie sich nach Abschluss die neue Dienst-ID, die Sie im nächsten Abschnitt benötigen.
  3. Erstellen Sie einen privaten Schlüssel für „Mit Apple anmelden“. Sie benötigen Ihren neuen privaten Schlüssel und die Schlüssel-ID im nächsten Abschnitt.
  4. Wenn Sie Funktionen von Firebase Authentication verwenden, mit denen E-Mails an Nutzer gesendet werden, z. B. die Anmeldung per E-Mail-Link, die Bestätigung der E-Mail-Adresse oder den Widerruf von Kontoänderungen, müssen Sie den privaten E-Mail-Relay-Dienst von Apple konfigurieren und noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (oder Ihre benutzerdefinierte E-Mail-Vorlagendomain) registrieren, damit Apple E-Mails, die von Firebase Authentication an anonymisierte Apple-E-Mail-Adressen gesendet werden, weiterleiten kann.

Apple als Anmeldeanbieter aktivieren

  1. Fügen Sie Ihrem Apple-Projekt Firebase hinzu. Registrieren Sie die Bundle-ID Ihrer App unbedingt, wenn Sie Ihre App in der Firebase Console einrichten.
  2. Öffnen Sie in der Firebase-Konsole den Bereich Auth (Authentifizierung). Aktivieren Sie auf dem Tab Anmeldemethode den Anbieter Apple. Geben Sie die Dienst-ID an, die Sie im vorherigen Abschnitt erstellt haben. Geben Sie außerdem im Abschnitt „OAuth-Code-Ablauf konfigurieren“ Ihre Apple-Team-ID sowie den privaten Schlüssel und die Schlüssel-ID an, die Sie im vorherigen Abschnitt erstellt haben.

Anforderungen von Apple für anonymisierte Daten einhalten

Mit „Mit Apple anmelden“ haben Nutzer die Möglichkeit, ihre Daten, einschließlich ihrer E-Mail-Adresse, bei der Anmeldung zu anonymisieren. Nutzer, die diese Option auswählen, haben E-Mail-Adressen mit der Domain privaterelay.appleid.com. Wenn Sie „Mit Apple anmelden“ in Ihrer App verwenden, müssen Sie alle anwendbaren Entwicklerrichtlinien oder ‑bedingungen von Apple bezüglich dieser anonymisierten Apple-IDs einhalten.

Außerdem müssen Sie die erforderliche Einwilligung des Nutzers einholen, bevor Sie direkt identifizierbare personenbezogene Daten mit einer anonymisierten Apple-ID verknüpfen. Wenn Sie die Firebase-Authentifizierung verwenden, kann dies die folgenden Aktionen umfassen:

  • Eine E‑Mail-Adresse mit einer anonymisierten Apple‑ID verknüpfen und umgekehrt
  • Telefonnummer mit einer anonymisierten Apple‑ID verknüpfen und umgekehrt
  • Nicht-anonyme Anmeldedaten für soziale Medien (Facebook, Google usw.) mit einer anonymisierten Apple-ID verknüpfen und umgekehrt

Die obige Liste ist nicht vollständig. In der Lizenzvereinbarung des Apple-Entwicklerprogramms im Mitgliedschaftsbereich Ihres Entwicklerkontos finden Sie Informationen dazu, ob Ihre App die Anforderungen von Apple erfüllt.

Über Apple anmelden und mit Firebase authentifizieren

Wenn Sie sich mit einem Apple-Konto authentifizieren möchten, melden Sie den Nutzer zuerst mit dem AuthenticationServices-Framework von Apple in seinem Apple-Konto an. Verwenden Sie dann das ID-Token aus der Antwort von Apple, um ein Firebase-AuthCredential-Objekt zu erstellen:

  1. Generieren Sie für jede Anmeldeanfrage einen zufälligen String – "Nonce", mit dem Sie prüfen, ob das ID-Token, das Sie erhalten, speziell als Antwort auf die Authentifizierungsanfrage der Anwendung gewährt wurde. Dieser Schritt ist wichtig, um Wiederholungsversuche zu verhindern.

    Mit SecRandomCopyBytes(_:_:_) können Sie eine kryptografisch sichere Nonce generieren, wie im folgenden Beispiel gezeigt:

    Swift

    private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      var randomBytes = [UInt8](repeating: 0, count: length)
      let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
      if errorCode != errSecSuccess {
        fatalError(
          "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
        )
      }
    
      let charset: [Character] =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
    
      let nonce = randomBytes.map { byte in
        // Pick a random character from the set, wrapping around if needed.
        charset[Int(byte) % charset.count]
      }
    
      return String(nonce)
    }
    
        

    Objective-C

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    - (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 copy];
    }
        

    Sie senden den SHA256-Hash der Nonce mit Ihrer Anmeldeanfrage, die Apple in der Antwort unverändert übergibt. Firebase validiert die Antwort, indem die ursprüngliche Nonce gehasht und mit dem von Apple übergebenen Wert verglichen wird.

    Swift

    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        String(format: "%02x", $0)
      }.joined()
    
      return hashString
    }
    
        

    Objective-C

    - (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;
    }
        
  2. Starten Sie den Anmeldevorgang von Apple und fügen Sie in Ihre Anfrage den SHA256-Hash des Nonce und die Delegate-Klasse ein, die die Antwort von Apple verarbeitet (siehe nächster Schritt):

    Swift

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

    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];
    }
    
  3. Verarbeiten Sie die Antwort von Apple in Ihrer Implementierung von ASAuthorizationControllerDelegate. Wenn die Anmeldung erfolgreich war, verwenden Sie das ID-Token aus der Antwort von Apple mit dem nicht gehashten Nonce zur Authentifizierung bei Firebase:

    Swift

    @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, including the user's full name.
          let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
                                                            rawNonce: nonce,
                                                            fullName: appleIDCredential.fullName)
          // 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, including the user's full name.
        FIROAuthCredential *credential = [FIROAuthProvider appleCredentialWithIDToken:IDToken
                                                                             rawNonce:self.appleRawNonce
                                                                             fullName:appleIDCredential.fullName];
    
        // 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);
    }
    

Anders als andere von Firebase Auth unterstützte Anbieter stellt Apple keine Foto-URL bereit.

Wenn der Nutzer seine E-Mail-Adresse nicht mit der App teilen möchte, stellt Apple eine eindeutige E-Mail-Adresse für diesen Nutzer bereit (im Format xyz@privaterelay.appleid.com), die mit Ihrer App geteilt wird. Wenn Sie den privaten E-Mail-Relay-Dienst konfiguriert haben, leitet Apple alle an die anonymisierte Adresse gesendeten E-Mails an die reale E-Mail-Adresse des Nutzers weiter.

Reauthentifizierung und Kontoverknüpfung

Dasselbe Muster kann mit reauthenticateWithCredential() verwendet werden. Damit können Sie ein neues Anmeldedaten-Token für vertrauliche Vorgänge abrufen, für die eine aktuelle Anmeldung erforderlich ist:

Swift

// 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.
  // ...
}];

Mit linkWithCredential() können Sie verschiedene Identitätsanbieter mit bestehenden Konten verknüpfen.

Hinweis: Apple setzt voraus, dass Sie die ausdrückliche Einwilligung der Nutzer einholen, bevor Sie ihre Apple-Konten mit anderen Daten verknüpfen.

Bei der Anmeldung mit Apple können Sie keine Anmeldedaten wiederverwenden, um eine Verknüpfung mit einem bestehenden Konto herzustellen. Wenn Sie Anmeldedaten für „Mit Apple anmelden“ mit einem anderen Konto verknüpfen möchten, müssen Sie zuerst versuchen, die Konten mit den alten Anmeldedaten für „Mit Apple anmelden“ zu verknüpfen. Untersuchen Sie dann den zurückgegebenen Fehler, um neue Anmeldedaten zu finden. Die neuen Anmeldedaten befinden sich im userInfo-Wörterbuch des Fehlers und können über den AuthErrorUserInfoUpdatedCredentialKey-Schlüssel aufgerufen werden.

Wenn Sie beispielsweise ein Facebook-Konto mit dem aktuellen Firebase-Konto verknüpfen möchten, verwenden Sie das Zugriffstoken, das Sie beim Anmelden des Nutzers bei Facebook erhalten haben:

Swift

// 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.
  // ...
}];

Tokenwiderruf

Apple verlangt, dass Nutzer in Apps, in denen Konten erstellt werden können, das Löschen ihres Kontos innerhalb der App initiieren können. Dies wird in den App Store Review Guidelines beschrieben.

Führen Sie dazu die folgenden Schritte aus:

  1. Achten Sie darauf, dass Sie den Abschnitt Services-ID und OAuth-Codeflusskonfiguration der Konfiguration des Anbieters „Mit Apple anmelden“ ausgefüllt haben, wie im Abschnitt Mit Apple anmelden konfigurieren beschrieben.

  2. Da Firebase keine Nutzer-Tokens speichert, wenn Nutzer mit „Mit Apple anmelden“ erstellt werden, müssen Sie den Nutzer bitten, sich noch einmal anzumelden, bevor Sie sein Token widerrufen und das Konto löschen.

    Swift

    private func deleteCurrentUser() {
      do {
        let nonce = try CryptoUtils.randomNonceString()
        currentNonce = nonce
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = CryptoUtils.sha256(nonce)
    
        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
      } catch {
        // In the unlikely case that nonce generation fails, show error view.
        displayError(error)
      }
    }
  3. Rufen Sie den Autorisierungscode von ASAuthorizationAppleIDCredential ab und verwenden Sie ihn, um Auth.auth().revokeToken(withAuthorizationCode:) aufzurufen und die Tokens des Nutzers zu widerrufen.

    Swift

    func authorizationController(controller: ASAuthorizationController,
                                 didCompleteWithAuthorization authorization: ASAuthorization) {
      guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential
      else {
        print("Unable to retrieve AppleIDCredential")
        return
      }
    
      guard let _ = currentNonce else {
        fatalError("Invalid state: A login callback was received, but no login request was sent.")
      }
    
      guard let appleAuthCode = appleIDCredential.authorizationCode else {
        print("Unable to fetch authorization code")
        return
      }
    
      guard let authCodeString = String(data: appleAuthCode, encoding: .utf8) else {
        print("Unable to serialize auth code string from data: \(appleAuthCode.debugDescription)")
        return
      }
    
      Task {
        do {
          try await Auth.auth().revokeToken(withAuthorizationCode: authCodeString)
          try await user?.delete()
          self.updateUI()
        } catch {
          self.displayError(error)
        }
      }
    }
  4. Löschen Sie das Nutzerkonto und alle zugehörigen Daten.

Nächste Schritte

Wenn sich ein Nutzer zum ersten Mal anmeldet, wird ein neues Nutzerkonto erstellt und mit den Anmeldedaten verknüpft, mit denen sich der Nutzer angemeldet hat, also mit dem Nutzernamen und Passwort, der Telefonnummer oder den Informationen des Authentifizierungsanbieters. Dieses neue Konto wird als Teil Ihres Firebase-Projekts gespeichert und kann verwendet werden, um einen Nutzer in allen Apps Ihres Projekts zu identifizieren, unabhängig davon, wie sich der Nutzer anmeldet.

  • In Ihren Apps können Sie die grundlegenden Profilinformationen des Nutzers aus dem User -Objekt abrufen. Weitere Informationen finden Sie unter Nutzer verwalten.

  • In Ihren Firebase Realtime Database- und Cloud Storage-Sicherheitsregeln können Sie die eindeutige Nutzer-ID des angemeldeten Nutzers aus der Variablen auth abrufen und damit steuern, auf welche Daten ein Nutzer zugreifen kann.

Sie können Nutzern erlauben, sich mit mehreren Authentifizierungsanbietern in Ihrer App anzumelden, indem Sie Anmeldedaten des Authentifizierungsanbieters mit einem vorhandenen Nutzerkonto verknüpfen.

Rufen Sie signOut: auf, um einen Nutzer abzumelden.

Swift

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

Möglicherweise möchten Sie auch Code zur Fehlerbehandlung für alle Authentifizierungsfehler hinzufügen. Weitere Informationen finden Sie unter Fehlerbehandlung.