Sie können zulassen, dass sich Ihre Nutzer mit ihrer Apple-ID bei Firebase authentifizieren. Dazu müssen Sie nur mit dem Firebase SDK, um den OAuth 2.0-End-to-End-Anmeldevorgang durchzuführen.
Hinweis
Damit du Nutzer über Apple anmelden kannst, musst du zuerst „Über Apple anmelden“ konfigurieren auf der Entwicklerwebsite von Apple ein und aktivieren Sie dann Apple als Anmeldeanbieter für Ihr Firebase-Projekt
Am Apple Developer Program teilnehmen
„Über Apple anmelden“ kann nur von Mitgliedern des Apple-Entwicklerprogramms konfiguriert werden.
„Über Apple anmelden“ konfigurieren
- Aktivieren Sie „Über Apple anmelden“ für Ihre App auf der Zertifikate, Kennungen und Profile der Entwickler-Website von Apple.
- Ihre Website wie im ersten Abschnitt beschrieben mit Ihrer App verknüpfen
Anleitung zum Konfigurieren von „Über Apple anmelden“ für das Web Registrieren Sie die
folgende URL als Return-URL verwenden:
Die Firebase-Projekt-ID finden Sie auf der Seite mit den Firebase-Konsoleneinstellungen. Notieren Sie sich anschließend Ihre neue Service-ID, die Sie in im nächsten Abschnitt.https://
YOUR_FIREBASE_PROJECT_ID .firebaseapp.com/__/auth/handler - Erstellen Sie einen privaten Schlüssel für „Mit Apple anmelden“. Sie benötigen Ihren neuen privaten Schlüssel und den neuen Schlüssel ID" ein.
- Wenn Sie eine der Funktionen von Firebase Authentication verwenden, über die E-Mails an Nutzer gesendet werden, z. B. die Anmeldung über einen E-Mail-Link, die Bestätigung der E-Mail-Adresse oder den Widerruf von Kontoänderungen, konfigurieren Sie den privaten E-Mail-Relay-Dienst von Apple und registrieren Sie
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com
(oder die Domain Ihrer benutzerdefinierten E-Mail-Vorlage), damit Apple von Firebase Authentication gesendete E-Mails an anonymisierte E-Mail-Adressen von Apple weiterleiten kann.
Apple als Anmeldeanbieter aktivieren
- Fügen Sie Ihrem Apple-Projekt Firebase hinzu. Registrieren Sie die Bundle-ID Ihrer App, wenn Sie sie in der Firebase-Konsole einrichten.
- Öffnen Sie in der Firebase Console den Bereich Auth. Gehen Sie auf dem Tab Anmeldemethode Aktivieren Sie den Apple-Anbieter. 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 an anonymisierte Daten von Apple erfüllen
Mit „Über 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 „Über Apple anmelden“ in Ihrer App verwenden, müssen Sie alle geltenden Entwicklerrichtlinien oder -bedingungen von Apple bezüglich dieser anonymisierten Apple-IDs einhalten.
Außerdem muss die Einwilligung des Nutzers eingeholt werden, bevor personenbezogene Daten mit einer anonymisierten Apple-ID verknüpft werden. Bei Verwendung von Firebase Authentication kann dies Folgendes umfassen: Aktionen:
- E-Mail-Adressen mit einer anonymisierten Apple-ID verknüpfen oder umgekehrt
- Telefonnummer mit einer anonymisierten Apple-ID verknüpfen oder umgekehrt
- Nicht-anonyme Anmeldedaten für soziale Medien (z. B. Facebook oder Google) mit einer anonymisierten Apple-ID verknüpfen und umgekehrt
Die obige Liste ist nicht vollständig. Lesen Sie die Lizenzvereinbarung des Apple-Entwicklerprogramms im Bereich „Mitgliedschaft“ Ihres Entwicklerkontos, um sicherzustellen, dass Ihre App die Anforderungen von Apple erfüllt.
Über Apple anmelden und mit Firebase authentifizieren
Damit Sie sich mit einem Apple-Konto authentifizieren können, müssen Sie den Nutzer zuerst in seinem Apple-Konto anmelden
mit dem AuthenticationServices
-Framework von Apple,
und dann das ID-Token aus der Antwort von Apple verwenden, um ein Firebase-Projekt zu erstellen,
AuthCredential
-Objekt:
Generieren Sie für jede Anmeldeanfrage einen zufälligen String – ein „Nonce“. So können 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.
Sie können eine kryptografisch sichere Nonce mit
SecRandomCopyBytes(_:_:_)
, wie im folgenden Beispiel: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) }
// 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]; }
Mit Ihrer Anmeldeanfrage senden Sie den SHA256-Hash der Nonce, der Apple wird in der Antwort unverändert übergeben. Firebase validiert die Antwort, indem die ursprüngliche Nonce gehasht und mit dem von Apple übergebenen Wert verglichen wird.
@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 }
- (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; }
Starten Sie den Anmeldevorgang von Apple und fügen Sie Ihrer Anfrage den SHA256-Hash der Nonce und die Delegate-Klasse hinzu, die die Antwort von Apple verarbeitet (siehe nächster Schritt):
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() }
@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]; }
Verarbeiten Sie die Antwort von Apple in Ihrer Implementierung von
ASAuthorizationControllerDelegate
. Wenn die Anmeldung erfolgreich war, verwenden Sie die ID. Token aus der Antwort von Apple mit der nicht gehashten Nonce für die Authentifizierung Firebase:@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)") } }
- (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); }
Im Gegensatz zu anderen von Firebase Auth unterstützten Anbietern stellt Apple keinen Foto-URL
Wenn der Nutzer seine E-Mail-Adresse nicht für die App freigibt,
stellt eine eindeutige E-Mail-Adresse für diesen Nutzer (im Formular
xyz@privaterelay.appleid.com
), die mit deiner App geteilt werden. Wenn Sie
den privaten E-Mail-Relay-Dienst konfiguriert, leitet Apple E-Mails an den
mit der echten E-Mail-Adresse des Nutzers verknüpfen.
Neue Authentifizierung und Kontoverknüpfung
Dasselbe Muster kann mit reauthenticateWithCredential()
verwendet werden, womit Sie
können neue Anmeldedaten für sensible Vorgänge abrufen, bei denen
letzte Anmeldung:
// 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.
// ...
}
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.
// ...
}];
Außerdem können Sie mit linkWithCredential()
verschiedene Identitätsanbieter mit vorhandenen Konten verknüpfen.
Beachten Sie, dass Sie bei Apple vor der Verknüpfung die ausdrückliche Einwilligung der Nutzer einholen müssen. mit anderen Daten verknüpfen.
Bei der Anmeldung über Apple können Sie Authentifizierungsdaten nicht wiederverwenden, um eine Verknüpfung zu einem
eines bestehenden Kontos. Wenn Sie Anmeldedaten für die Funktion „Über Apple anmelden“ mit einem anderen Konto verknüpfen möchten, müssen Sie zuerst versuchen, die Konten mit den alten Anmeldedaten für die Funktion „Über Apple anmelden“ zu verknüpfen. Prüfen Sie dann den zurückgegebenen Fehler, um neue Anmeldedaten zu finden.
Die neuen Anmeldedaten befinden sich im Wörterbuch userInfo
des Fehlers und können
kann über den Schlüssel AuthErrorUserInfoUpdatedCredentialKey
aufgerufen werden.
Wenn Sie beispielsweise ein Facebook-Konto mit dem aktuellen Firebase-Konto verknüpfen möchten, verwenden Sie die Methode Zugriffstoken, das Sie bei der Anmeldung des Nutzers bei Facebook erhalten haben:
// 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.
// ...
}
// 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.
// ...
}];
Widerruf von Tokens
Apple verlangt, dass Nutzer in Apps, die die Kontoerstellung unterstützen, Löschung ihres Kontos innerhalb der App, wie im Artikel App Store Review (Rezension zum App Store) beschrieben Richtlinien
Führen Sie die folgenden Schritte aus, um diese Anforderung zu erfüllen:
Achten Sie darauf, dass Sie die Abschnitte Services-ID und OAuth-Codeflusskonfiguration in der Konfiguration des Anbieters „Über Apple anmelden“ ausgefüllt haben, wie im Abschnitt „Über Apple anmelden“ konfigurieren beschrieben.
Da Firebase keine Nutzertokens speichert, wenn Nutzer mit „Über Apple anmelden“ erstellt werden, müssen Sie den Nutzer bitten, sich noch einmal anzumelden, bevor Sie sein Token widerrufen und das Konto löschen.
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) } }
Rufen Sie den Autorisierungscode von der
ASAuthorizationAppleIDCredential
ab. können Sie damitAuth.auth().revokeToken(withAuthorizationCode:)
aufrufen, um die die Tokens des Nutzers.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) } } }
Löschen Sie abschließend das Nutzerkonto und alle zugehörigen Daten.
Nächste Schritte
Nachdem sich ein Nutzer zum ersten Mal angemeldet hat, wird ein neues Nutzerkonto erstellt und mit den Anmeldedaten verknüpft, d. h. mit dem Nutzernamen und Passwort, der Telefonnummer oder den Informationen zum Authentifizierungsanbieter, mit denen sich der Nutzer angemeldet hat. Dieses neue Konto wird als Teil Ihres Firebase-Projekts gespeichert und kann verwendet werden, um einen Nutzer in allen Apps in Ihrem Projekt zu identifizieren, unabhängig davon, wie er sich anmeldet.
-
In Ihren Apps können Sie die grundlegenden Profilinformationen des Nutzers über das
User
-Objekt abrufen. Weitere Informationen finden Sie unter Nutzer verwalten. In Firebase Realtime Database und Cloud Storage Sicherheitsregeln können Sie die eindeutige Nutzer-ID des angemeldeten Nutzers aus der Variablen
auth
abrufen, und steuern, auf welche Daten ein Nutzer zugreifen kann.
Sie können Nutzern erlauben, sich über mehrere Authentifizierungsanbieter in Ihrer App anzumelden, indem Sie Anmeldedaten des Authentifizierungsanbieters mit einem vorhandenen Nutzerkonto verknüpfen.
Wenn Sie einen Nutzer abmelden möchten, rufen Sie signOut:
auf.
let firebaseAuth = Auth.auth() do { try firebaseAuth.signOut() } catch let signOutError as NSError { print("Error signing out: %@", signOutError) }
NSError *signOutError; BOOL status = [[FIRAuth auth] signOut:&signOutError]; if (!status) { NSLog(@"Error signing out: %@", signOutError); return; }
Sie können auch Code zur Fehlerbehandlung für alle Authentifizierungsfehler hinzufügen. Siehe Fehler beheben.