Aby zezwolić użytkownikom na uwierzytelnianie w Firebase za pomocą ich Apple ID: używając pakietu SDK Firebase do przeprowadzenia pełnego logowania OAuth 2.0.
Zanim zaczniesz
Aby zalogować użytkowników przy użyciu urządzenia Apple, najpierw skonfiguruj funkcję Zaloguj się przez Apple w witrynie Apple dla deweloperów, a potem włącz Apple jako dostawcę logowania projekt Firebase.
Dołącz do programu dla deweloperów Apple
Funkcja Zaloguj się przez Apple może skonfigurować tylko członkowie Apple Developer Program.
Skonfiguruj logowanie się przez Apple
- Włącz funkcję Zaloguj się przez Apple w swojej aplikacji na Certyfikaty, identyfikatory Profile w witrynie Apple dla deweloperów.
- Powiąż witrynę z aplikacją w sposób opisany w pierwszej sekcji
artykułu Konfigurowanie logowania przez Apple w przeglądarce. Gdy pojawi się odpowiedni komunikat, zarejestruj
następujący adres URL jako powrotny adres URL:
https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
Identyfikator projektu Firebase znajdziesz na stronie ustawień konsoli Firebase. Gdy skończysz, zapisz nowy identyfikator usługi, który będzie Ci potrzebny w przejdź do następnej sekcji. - Utwórz Zaloguj się za pomocą klucza prywatnego Apple. Potrzebujesz nowego klucza prywatnego i klucza Identyfikator znajdziesz w następnej sekcji.
- Jeśli używasz dowolnej funkcji Firebase Authentication, która wysyła e-maile do użytkowników,
w tym logowanie za pomocą linku e-mail, weryfikacja adresu e-mail, zmiana konta
unieważnienie
w innych, skonfigurować usługę Apple Private Mail relay
i zarejestruj się
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com
(lub dostosowanej domeny szablonu e-maila), dzięki czemu Apple może przekazywać wysyłane e-maile. od Firebase Authentication na zanonimizowane adresy e-mail Apple.
Włącz Apple jako dostawcę logowania
- Dodaj Firebase do projektu Apple. Koniecznie zarejestruj identyfikator pakietu aplikacji podczas konfigurowania aplikacji w Konsola Firebase.
- W konsoli Firebase otwórz sekcję Uwierzytelnianie. Na karcie Metoda logowania: włącz dostawcę Apple. Podaj identyfikator usługi utworzony w poprzedniej sekcji. Ponadto w Sekcja konfiguracji przepływu kodu OAuth, podaj identyfikator zespołu Apple oraz klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.
Zgodność z wymaganiami firmy Apple dotyczącymi zanonimizowanych danych
Zaloguj się przez Apple umożliwia anonimizację danych użytkowników,
łącznie z jego adresem e-mail. Użytkownicy, którzy wybiorą tę opcję
mają adresy e-mail w domenie privaterelay.appleid.com
. Kiedy
korzystasz w aplikacji z funkcji Zaloguj się przez Apple, musisz przestrzegać wszystkich obowiązujących
zasady dla deweloperów lub warunki firmy Apple dotyczące tych zanonimizowanych
Identyfikatory.
Obejmuje to uzyskanie wymaganej zgody użytkownika przed kojarzyć żadnych danych osobowych bezpośrednio umożliwiających identyfikację ze zanonimizowanymi danymi firmy Apple ID. Gdy korzystasz z Uwierzytelniania Firebase, może to obejmować: czynności:
- Połącz adres e-mail z anonimowym identyfikatorem Apple ID lub odwrotnie.
- Łączenie numeru telefonu z anonimowym identyfikatorem Apple ID i odwrotnie
- Połącz nieanonimowe dane społecznościowe (Facebook, Google itp.) z lub na odwrót.
Powyższa lista nie jest wyczerpująca. Zapoznaj się z informacjami o programie dla deweloperów Apple Umowę licencyjną w sekcji Członkostwo na koncie dewelopera, aby upewnić się, że Twoja aplikacja spełnia wymagania Apple.
Zaloguj się przez Apple i uwierzytelnij się w Firebase
Aby uwierzytelnić się za pomocą konta Apple, najpierw zaloguj użytkownika na jego koncie Apple
z kontem firmy Apple AuthenticationServices
,
a następnie użyj tokena identyfikatora z odpowiedzi Apple do utworzenia Firebase
Obiekt AuthCredential
:
Dla każdego żądania logowania wygeneruj losowy ciąg znaków, „nonce” – służy do sprawdzenia, czy otrzymany token przyznanych w odpowiedzi na żądanie uwierzytelnienia aplikacji. Ten jest ważny, aby zapobiec atakom typu „replay”.
Możesz wygenerować kryptograficznie zabezpieczoną liczbę jednorazową za pomocą
SecRandomCopyBytes(_:_:_)
jak w tym przykładzie: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]; }
W żądaniu logowania wysyłasz hasz SHA256 identyfikatora jednorazowego, który Apple przekazuje w odpowiedzi niezmienioną treść. Firebase weryfikuje odpowiedź. przez zaszyfrowanie oryginalnej liczby jednorazowej i porównanie jej z wartością przekazaną przez Apple.
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; }
Uruchom proces logowania Apple, uwzględnij w żądaniu identyfikator SHA256 liczbę jednorazową i klasę delegata, która będzie obsługiwać odpowiedź Apple (zobacz następny krok):
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]; }
Obsłuż odpowiedź Apple w swojej implementacji
ASAuthorizationControllerDelegate
Jeśli udało Ci się zalogować, użyj identyfikatora token z odpowiedzi Apple z niezaszyfrowaną liczbą jednorazową do uwierzytelnienia 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); }
W przeciwieństwie do innych dostawców obsługiwanych przez Uwierzytelnienie Firebase Apple nie udostępnia adresu URL zdjęcia.
Ponadto, jeśli użytkownik zdecyduje się nie udostępniać aplikacji e-mail, Apple
udostępnia danemu użytkownikowi niepowtarzalny adres e-mail (w formie formularza
xyz@privaterelay.appleid.com
), które udostępnia Twojej aplikacji. Jeśli
jeśli skonfigurujesz usługę prywatnej usługi przekaźnika poczty e-mail, Apple przekazuje e-maile wysyłane na
anonimowy adres e-mail użytkownika.
Ponowne uwierzytelnianie i łączenie kont
Tego samego wzoru można użyć z zasadą reauthenticateWithCredential()
, którą
może służyć do pobierania nowych danych logowania w przypadku operacji poufnych, które wymagają
ostatnie logowanie:
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.
// ...
}];
Za pomocą linkWithCredential()
możesz też łączyć różnych dostawców tożsamości z
istniejących kont.
Pamiętaj, że firma Apple wymaga od użytkowników uzyskania wyraźnej zgody przed połączeniem swoje konta Apple do innych danych.
Funkcja Zaloguj się przez Apple nie będzie zezwalać na ponowne użycie danych uwierzytelniających w celu połączenia z
istniejącego konta. Jeśli chcesz połączyć dane logowania w ramach funkcji Zaloguj się przez Apple z innym
konta, musisz najpierw spróbować połączyć konta, korzystając ze starego konta Zaloguj się przez
dane logowania Apple, a następnie sprawdź zwrócony błąd, aby znaleźć nowe dane logowania.
Nowe dane logowania będą znajdować się w słowniku userInfo
błędu i mogą być
można uzyskać za pomocą klawisza AuthErrorUserInfoUpdatedCredentialKey
.
Aby na przykład połączyć konto na Facebooku z bieżącym kontem Firebase, użyj funkcji token dostępu uzyskany po zalogowaniu użytkownika na Facebooku:
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.
// ...
}];
Unieważnienie tokena
Apple wymaga, aby aplikacje umożliwiające tworzenie kont mogły inicjować działania użytkowników usunięcia konta w aplikacji, zgodnie z opisem w Informacjach na temat App Store Wytyczne
Aby spełnić to wymaganie, wykonaj następujące czynności:
Upewnij się, że zostały wypełnione pola Identyfikator usług i Konfiguracja procesu kodu OAuth. konfiguracji funkcji Zaloguj się przez Apple, jak opisano Skonfiguruj funkcję Zaloguj się przez Apple.
Firebase nie przechowuje tokenów użytkowników tworzonych za pomocą Zaloguj się przez Apple, zanim cofniesz zaproszenie, musisz poprosić użytkownika o ponowne zalogowanie się token i usunięcie konta.
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) } }
uzyskać kod autoryzacji ze strony
ASAuthorizationAppleIDCredential
, użyj go do wywołaniaAuth.auth().revokeToken(withAuthorizationCode:)
w celu unieważnienia tokeny użytkownika.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) } } }
Na koniec usuń konto użytkownika (i wszystkie powiązane z nim dane).
Dalsze kroki
Gdy użytkownik zaloguje się po raz pierwszy, tworzone jest nowe konto użytkownika. powiązane z danymi logowania, czyli z nazwą użytkownika, hasłem i numerem telefonu, numer telefonu lub informacje o dostawcy uwierzytelniania – użytkownik zalogowany. Ten nowy jest przechowywane w ramach projektu Firebase i może służyć do identyfikowania użytkownika w każdej aplikacji w projekcie, niezależnie od tego, jak się loguje.
-
W swoich aplikacjach możesz uzyskać podstawowe informacje o profilu użytkownika z
User
. Zobacz Zarządzanie użytkownikami. Na liście Firebase Realtime Database i Cloud Storage regułami zabezpieczeń, pobierz ze zmiennej
auth
unikalny identyfikator zalogowanego użytkownika, i używać ich do kontrolowania, do jakich danych użytkownik ma dostęp.
Możesz zezwolić użytkownikom na logowanie się w aplikacji przy użyciu wielokrotnego uwierzytelniania. dostawców, łącząc dane logowania dostawcy uwierzytelniania z istniejącego konta użytkownika.
Aby wylogować użytkownika, wywołaj
signOut:
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; }
Można także dodać kod obsługi błędów dla pełnego zakresu uwierzytelniania . Patrz Obsługa błędów.