Uwierzytelnij przez Apple i C++

Możesz zezwolić użytkownikom na uwierzytelnianie w Firebase za pomocą Apple ID, korzystając z pakietu Firebase SDK do przeprowadzania kompleksowego procesu logowania OAuth 2.0.

Zanim zaczniesz

Aby logować użytkowników za pomocą Apple, najpierw skonfiguruj logowanie przez Apple na stronie dla deweloperów Apple, a potem włącz Apple jako dostawcę logowania w projekcie Firebase.

Dołączanie do programu Apple Developer Program

Logowanie przez Apple mogą konfigurować tylko uczestnicy programu Apple Developer.

Konfigurowanie logowania się przez Apple

Logowanie przez Apple musi być włączone i prawidłowo skonfigurowane w projekcie Firebase. Konfiguracja różni się w zależności od platformy Android i Apple. Zanim przejdziesz dalej, zapoznaj się z sekcją „Konfigurowanie logowania za pomocą Apple” w przewodnikach dotyczących platform Apple lub Androida.

Włączanie Apple jako dostawcy logowania

  1. W Firebasekonsoli otwórz sekcję Uwierzytelnianie. Na karcie Metoda logowania włącz dostawcę Apple.
  2. Skonfiguruj ustawienia dostawcy logowania przez Apple:
    1. Jeśli wdrażasz aplikację tylko na platformach Apple, możesz pozostawić puste pola Identyfikator usługi, Identyfikator zespołu Apple, Klucz prywatny i Identyfikator klucza.
    2. Pomoc dotycząca urządzeń z Androidem:
      1. Dodaj Firebase do projektu na Androida. Podczas konfigurowania aplikacji w Firebase konsoli zarejestruj podpis SHA-1 aplikacji.
      2. W konsoli Firebase otwórz sekcję Uwierzytelnianie. Na karcie Metoda logowania włącz dostawcę Apple. Określ identyfikator usługi utworzony w poprzedniej sekcji. W sekcji konfiguracji procesu OAuth podaj też identyfikator zespołu Apple, klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.

Zapewnianie zgodności z wymaganiami Apple dotyczącymi danych anonimizowanych

Logowanie przez Apple umożliwia użytkownikom anonimizację danych, w tym adresu e-mail, podczas logowania. Użytkownicy, którzy wybiorą tę opcję, będą mieć adresy e-mail z domeną privaterelay.appleid.com. Jeśli w aplikacji używasz funkcji Zaloguj się przez Apple, musisz przestrzegać wszelkich obowiązujących zasad lub warunków dla deweloperów firmy Apple dotyczących tych zanonimizowanych identyfikatorów Apple.

Obejmuje to uzyskanie wymaganej zgody użytkownika przed powiązaniem bezpośrednio identyfikujących danych osobowych z zanonimizowanym identyfikatorem Apple ID. W przypadku korzystania z Uwierzytelniania Firebase mogą to być te działania:

  • Połącz adres e-mail z anonimizowanym identyfikatorem Apple ID lub odwrotnie.
  • Łączenie numeru telefonu z zanonimizowanym identyfikatorem Apple ID i odwrotnie
  • połączenie nieanonimowych danych logowania w usługach społecznościowych (Facebook, Google itp.) ze zanonimizowanym identyfikatorem Apple ID lub odwrotnie;

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

Dostęp do zajęć firebase::auth::Auth

Klasa Auth jest bramą dla wszystkich wywołań interfejsu API.
  1. Dodaj pliki nagłówkowe Auth i App:
    #include "firebase/app.h"
    #include "firebase/auth.h"
  2. W kodzie inicjowania utwórz klasę firebase::App.
    #if defined(__ANDROID__)
      firebase::App* app =
          firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity);
    #else
      firebase::App* app = firebase::App::Create(firebase::AppOptions());
    #endif  // defined(__ANDROID__)
  3. Uzyskaj dostęp do zajęć firebase::auth::Auth dla firebase::App. Istnieje bezpośrednie powiązanie między AppAuth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);

Obsługa procesu logowania za pomocą pakietu Firebase SDK

Proces logowania się przez Apple różni się na platformach Apple i Android.

Na platformach Apple

Uwierzytelniaj użytkowników za pomocą Firebase przy użyciu pakietu SDK Apple Sign In Objective-C wywoływanego z kodu C++.

  1. W przypadku każdego żądania logowania wygeneruj losowy ciąg znaków – „nonce” – który posłuży Ci do sprawdzenia, czy otrzymany token identyfikatora został przyznany w odpowiedzi na żądanie uwierzytelniania aplikacji. Ten krok jest ważny, aby zapobiec atakom metodą powtórzenia.

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

    W żądaniu logowania wyślesz identyfikator SHA256 wartości jednorazowej, który Apple przekaże w odpowiedzi bez zmian. Firebase weryfikuje odpowiedź, haszując oryginalny nonce i porównując go z wartością przekazaną przez Apple.

  2. Uruchom proces logowania w Apple, w tym w żądaniu hasz SHA256 nonce i klasę delegata, która będzie obsługiwać odpowiedź Apple (patrz następny krok):

      - (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. Obsłuż odpowiedź Apple w implementacji protokołu `ASAuthorizationControllerDelegate`. Jeśli logowanie się powiodło, użyj tokena tożsamości z odpowiedzi Apple z niezaszyfrowanym jednorazowym kodem do uwierzytelniania w Firebase:

      - (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);
          }
        }
    
  4. Użyj otrzymanego ciągu tokena i oryginalnego nonce, aby utworzyć FirebaseCredential i zalogować się w Firebase.

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  5. Ten sam wzorzec można stosować w przypadku funkcji Reauthenticate, która umożliwia pobieranie nowych danych logowania do operacji związanych z poufnymi danymi, które wymagają niedawnego zalogowania się.

    firebase::Future<firebase::auth::AuthResult> result =
        user->Reauthenticate(credential);
    
  6. Ten sam wzorzec można zastosować do połączenia konta z funkcją logowania przez Apple. Może jednak wystąpić błąd, jeśli istniejące konto Firebase zostało już połączone z kontem Apple, z którym próbujesz utworzyć połączenie. W takim przypadku obiekt Future zwróci stan kAuthErrorCredentialAlreadyInUse, a AuthResult może zawierać prawidłowy obiekt credential. Tych danych logowania można używać do logowania się na połączone z Apple konto za pomocą SignInAndRetrieveDataWithCredential bez konieczności generowania kolejnego tokena logowania Apple i wartości nonce.

    firebase::Future<firebase::auth::AuthResult> link_result =
        auth->current_user().LinkWithCredential(credential);
    
    // To keep example simple, wait on the current thread until call completes.
    while (link_result.status() == firebase::kFutureStatusPending) {
      Wait(100);
    }
    
    // Determine the result of the link attempt
    if (link_result.error() == firebase::auth::kAuthErrorNone) {
      // user linked correctly.
    } else if (link_result.error() ==
                   firebase::auth::kAuthErrorCredentialAlreadyInUse &&
               link_result.result()
                   ->additional_user_info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::AuthResult> result =
          auth->SignInAndRetrieveDataWithCredential(
              link_result.result()->additional_user_info.updated_credential);
    } else {
      // Another link error occurred.
    }

W Androidzie

Na Androidzie uwierzytelniaj użytkowników za pomocą Firebase, integrując w aplikacji ogólne logowanie OAuth oparte na internecie za pomocą pakietu Firebase SDK, aby przeprowadzić cały proces logowania.

Aby obsłużyć proces logowania za pomocą pakietu Firebase SDK, wykonaj te czynności:

  1. Utwórz instancję FederatedOAuthProviderData skonfigurowaną z identyfikatorem dostawcy odpowiednim dla Apple.

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. Opcjonalnie: określ dodatkowe zakresy OAuth 2.0 poza domyślnymi, o które chcesz poprosić dostawcę uwierzytelniania.

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. Opcjonalnie: jeśli chcesz, aby ekran logowania Apple był wyświetlany w języku innym niż angielski, ustaw parametr locale. Listę obsługiwanych ustawień regionalnych znajdziesz w dokumentacji Logowania przez Apple.

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. Po skonfigurowaniu danych dostawcy użyj ich do utworzenia obiektu FederatedOAuthProvider.

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. Uwierzytelnij się w Firebase za pomocą obiektu dostawcy uwierzytelniania. Pamiętaj, że w przeciwieństwie do innych operacji FirebaseAuth ta operacja przejmie kontrolę nad interfejsem, wyświetlając widok internetowy, w którym użytkownik może wpisać swoje dane logowania.

    Aby rozpocząć proces logowania, wywołaj funkcję signInWithProvider:

    firebase::Future<firebase::auth::AuthResult> result =
      auth->SignInWithProvider(provider_data);
    

    Aplikacja może wtedy czekać lub zarejestrować wywołanie zwrotne w obiekcie Future.

  6. Ten sam wzorzec można stosować w przypadku funkcji ReauthenticateWithProvider, która umożliwia pobieranie nowych danych logowania do operacji związanych z poufnymi danymi, które wymagają niedawnego zalogowania się.

    firebase::Future<firebase::auth::AuthResult> result =
      user.ReauthenticateWithProvider(provider_data);
    

    Aplikacja może wtedy poczekać lub zarejestrować wywołanie zwrotne w obiekcie Future.

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

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

    Aby na przykład połączyć konto Facebook z bieżącym kontem Firebase, użyj tokena dostępu uzyskanego podczas logowania użytkownika na Facebooku:

    // Initialize a Facebook credential with a Facebook access token.
    AuthCredential credential =
        firebase::auth::FacebookAuthProvider.getCredential(token);
    
    // Assuming the current user is an Apple user linking a Facebook provider.
    firebase::Future<firebase::auth::AuthResult> result =
        auth.current_user().LinkWithCredential(credential);
    

Logowanie się za pomocą Notatek Apple

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

Gdy użytkownik zdecyduje się nie udostępniać aplikacji swojego adresu e-mail, Apple udostępnia mu unikalny adres e-mail (w formacie xyz@privaterelay.appleid.com), który jest udostępniany Twojej aplikacji. Jeśli skonfigurujesz usługę przekaźnika prywatnego adresu e-mail, Apple będzie przekazywać e-maile wysyłane na anonimowy adres na prawdziwy adres e-mail użytkownika.

Apple udostępnia aplikacjom informacje o użytkowniku, takie jak nazwa wyświetlana, tylko przy pierwszym logowaniu. Zwykle Firebase zapisuje nazwę wyświetlaną przy pierwszym logowaniu użytkownika za pomocą Apple. Możesz ją uzyskać za pomocą current_user().display_name(). Jeśli jednak wcześniej użytkownik logował się w aplikacji za pomocą Apple bez użycia Firebase, Apple nie przekaże Firebase nazwy wyświetlanej użytkownika.

Dalsze kroki

Gdy użytkownik zaloguje się po raz pierwszy, zostanie utworzone nowe konto użytkownika i powiązane z danymi logowania, czyli nazwą użytkownika i hasłem, numerem telefonu lub informacjami o dostawcy uwierzytelniania, za pomocą których użytkownik się zalogował. To nowe konto jest przechowywane w projekcie Firebase i może służyć do identyfikowania użytkownika we wszystkich aplikacjach w projekcie, niezależnie od sposobu logowania.

W aplikacjach możesz uzyskać podstawowe informacje o profilu użytkownika z obiektu firebase::auth::User. Zobacz Zarządzanie użytkownikami.

W regułach zabezpieczeń Bazy danych czasu rzeczywistego Firebase i Cloud Storage możesz uzyskać niepowtarzalny identyfikator użytkownika, który jest zalogowany, z zmiennej auth i użyć go do kontrolowania, do jakich danych użytkownik ma dostęp.