Google is committed to advancing racial equity for Black communities. See how.
Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Uwierzytelnij się za pomocą Apple na iOS

Możesz pozwolić swoim użytkownikom na uwierzytelnianie w Firebase przy użyciu ich identyfikatora Apple ID, używając pakietu SDK Firebase, aby przeprowadzić pełny proces logowania OAuth 2.0.

Zanim zaczniesz

Aby logować użytkowników za pomocą Apple, najpierw skonfiguruj opcję Zaloguj się za pomocą Apple w witrynie programistów Apple, a następnie włącz Apple jako dostawcę logowania do projektu Firebase.

Dołącz do programu Apple Developer

Logowanie za pomocą Apple może być skonfigurowane tylko przez członków programu Apple Developer Program .

Skonfiguruj logowanie za pomocą Apple

  1. Włącz opcję Zaloguj się przez Apple dla swojej aplikacji na stronie Certyfikaty, identyfikatory i profile w witrynie programistów Apple.
  2. Jeśli korzystasz z którejkolwiek z funkcji uwierzytelniania Firebase, które wysyłają wiadomości e-mail do użytkowników, w tym logowania za pomocą łącza e-mail, weryfikacji adresu e-mail, odwołania zmiany konta i innych, skonfiguruj prywatną usługę przekazywania poczty e-mail Apple i zarejestruj się noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (lub niestandardowa domena szablonów wiadomości e-mail), aby firma Apple mogła przekazywać wiadomości e-mail wysyłane przez uwierzytelnianie Firebase na anonimowe adresy e-mail Apple.

Włącz Apple jako dostawcę logowania

  1. Dodaj Firebase do swojego projektu na iOS . Pamiętaj, aby zarejestrować identyfikator pakietu aplikacji podczas konfigurowania aplikacji w konsoli Firebase.
  2. W konsoli Firebase otwórz sekcję Auth . Na karcie Metoda logowania włącz dostawcę Apple . Jeśli używasz tylko opcji Zaloguj się przez Apple w aplikacji na iOS, możesz pozostawić pola Service ID, Apple Team ID, klucz prywatny i ID klucza puste.

Przestrzegaj wymagań Apple dotyczących anonimowych danych

Sign In with Apple daje użytkownikom możliwość anonimizacji ich danych, w tym adresu e-mail, podczas logowania. Użytkownicy, którzy wybiorą tę opcję, mają adresy e-mail z domeną privaterelay.appleid.com . Korzystając z funkcji Zaloguj się przez Apple w swojej aplikacji, musisz przestrzegać wszelkich obowiązujących zasad lub warunków dla programistów Apple dotyczących tych anonimowych identyfikatorów Apple ID.

Obejmuje to uzyskanie wymaganej zgody użytkownika przed powiązaniem jakichkolwiek danych osobowych umożliwiających bezpośrednią identyfikację z anonimowym identyfikatorem Apple ID. W przypadku korzystania z uwierzytelniania Firebase może to obejmować następujące działania:

  • Połącz adres e-mail z anonimowym identyfikatorem Apple ID lub odwrotnie.
  • Połącz numer telefonu z anonimowym identyfikatorem Apple ID lub odwrotnie
  • Połącz nieanonimowe dane logowania społecznościowego (Facebook, Google itp.) Z anonimowym identyfikatorem Apple ID lub odwrotnie.

Powyższa lista nie jest wyczerpująca. Zapoznaj się z umową licencyjną programu Apple Developer w sekcji Członkostwo na koncie programisty, aby upewnić się, że aplikacja spełnia wymagania Apple.

Zaloguj się w Apple i uwierzytelnij w Firebase

Aby uwierzytelnić się za pomocą konta Apple, najpierw zaloguj się użytkownika na jego konto Apple przy użyciu struktury AuthenticationServices firmy Apple, a następnie użyj tokenu ID z odpowiedzi Apple, aby utworzyć obiekt AuthCredential :

  1. Dla każdego żądania logowania wygeneruj losowy ciąg - „jednorazowy” - którego użyjesz, aby upewnić się, że otrzymany token identyfikatora został przyznany w odpowiedzi na żądanie uwierzytelnienia aplikacji. Ten krok jest ważny, aby zapobiec atakom powtórkowym.

    Możesz wygenerować kryptograficznie bezpieczny SecRandomCopyBytes(_:_:_) w systemie iOS za pomocą SecRandomCopyBytes(_:_:_) , jak w poniższym przykładzie:

    Szybki

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

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

    Wraz z żądaniem logowania wyślesz skrót SHA256 wartości jednorazowej, który Apple przekaże bez zmian w odpowiedzi. Firebase sprawdza odpowiedź, haszując pierwotną wartość jednorazową i porównując ją z wartością przekazaną przez Apple.

  2. Uruchom proces logowania Apple, w tym w swoim żądaniu skrót SHA256 wartości jednorazowej i klasę delegata, która będzie obsługiwać odpowiedź Apple (zobacz następny krok):

    Szybki

    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
    }
    

    Cel 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 odpowiedź Apple w swojej implementacji ASAuthorizationControllerDelegate . Jeśli logowanie się powiodło, użyj tokena identyfikatora z odpowiedzi Apple z niezaszyfrowanym numerem jednorazowym, aby uwierzytelnić się w Firebase:

    Szybki

    @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)")
      }
    
    }
    

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

W przeciwieństwie do innych dostawców obsługiwanych przez Firebase Auth, Apple nie udostępnia adresu URL zdjęcia.

Ponadto, gdy użytkownik zdecyduje się nie udostępniać swojego adresu e-mail aplikacji, Apple zapewnia mu unikatowy adres e-mail (w postaci xyz@privaterelay.appleid.com ), który udostępnia Twojej aplikacji. Jeśli skonfigurowałeś prywatną usługę przekazywania poczty e-mail, Apple przekazuje wiadomości e-mail wysłane na anonimowy adres na rzeczywisty adres e-mail użytkownika.

Apple udostępnia aplikacjom informacje o użytkowniku, takie jak nazwa wyświetlana, tylko przy pierwszym Auth.auth().currentUser.displayName użytkownika. Zwykle Firebase przechowuje nazwę wyświetlaną przy pierwszym Auth.auth().currentUser.displayName użytkownika w Apple, którą można uzyskać za pomocą Auth.auth().currentUser.displayName . Jeśli jednak wcześniej używałeś Apple do logowania użytkownika do aplikacji bez korzystania z Firebase, Apple nie udostępni Firebase wyświetlanej nazwy użytkownika.

Ponowne uwierzytelnienie i łączenie kont

Tego samego wzorca można użyć z reauthenticateWithCredential() , której można użyć do pobrania nowego poświadczenia dla poufnych operacji, które wymagają niedawnego logowania:

Szybki

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

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

Możesz też użyć funkcji linkWithCredential() aby połączyć różnych dostawców tożsamości z istniejącymi kontami.

Pamiętaj, że Apple wymaga uzyskania wyraźnej zgody od użytkowników przed połączeniem ich kont Apple z innymi danymi.

Logowanie za pomocą Apple nie pozwala na ponowne użycie poświadczeń uwierzytelniania w celu połączenia z istniejącym kontem. Jeśli chcesz połączyć logowanie przy użyciu poświadczeń Apple z innym kontem, musisz najpierw spróbować połączyć konta przy użyciu starego logowania z poświadczeniami Apple, a następnie sprawdzić zwrócony błąd, aby znaleźć nowe poświadczenie. Nowe poświadczenie zostanie umieszczone w słowniku userInfo błędu i będzie można uzyskać do niego dostęp za pośrednictwem klucza FIRAuthErrorUserInfoUpdatedCredentialKey .

Na przykład, aby połączyć konto na Facebooku z bieżącym kontem Firebase, użyj tokena dostępu, który otrzymałeś podczas logowania użytkownika na Facebooku:

Szybki

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

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

Następne kroki

Gdy użytkownik loguje się po raz pierwszy, tworzone jest nowe konto użytkownika i jest ono łączone z poświadczeniami - czyli nazwą użytkownika i hasłem, numerem telefonu lub informacjami dostawcy uwierzytelniania - zalogowanym użytkownikiem. To nowe konto jest przechowywane jako część projektu Firebase i może służyć do identyfikacji użytkownika we wszystkich aplikacjach w Twoim projekcie, niezależnie od tego, w jaki sposób się on loguje.

  • W swoich aplikacjach możesz uzyskać podstawowe informacje o profilu użytkownika z obiektu FIRUser . Zobacz Zarządzanie użytkownikami .

  • W swoich regułach bezpieczeństwa Firebase Realtime Database i Cloud Storage możesz uzyskać unikalny identyfikator zalogowanego użytkownika ze zmiennej auth i użyć go do kontrolowania, do jakich danych użytkownik ma dostęp.

Możesz zezwolić użytkownikom na logowanie się do aplikacji przy użyciu wielu dostawców uwierzytelniania, łącząc poświadczenia dostawcy uwierzytelniania z istniejącym kontem użytkownika.

Aby wylogować użytkownika, wywołaj signOut:

Szybki

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

Cel C

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

Możesz również chcieć dodać kod obsługi błędów dla pełnego zakresu błędów uwierzytelniania. Zobacz Obsługa błędów .