Catch up on everthing we announced at this year's Firebase Summit. Learn more

使用 Apple 和 C++ 進行身份驗證

通過使用 Firebase SDK 執行端到端 OAuth 2.0 登錄流程,您可以讓您的用戶使用他們的 Apple ID 向 Firebase 進行身份驗證。

在你開始之前

要使用 Apple 登錄用戶,請首先在 Apple 的開發者網站上配置使用 Apple 登錄,然後啟用 Apple 作為 Firebase 項目的登錄提供程序。

加入 Apple 開發者計劃

登錄與蘋果只能由成員進行配置的蘋果開發者計劃

配置使用 Apple 登錄

必須在 Firebase 項目中啟用並正確配置 Apple 登錄。配置因 Android 和 Apple 平台而異。請按照“配置登錄隨著蘋果”的部分蘋果平台和/或Android的繼續之前的指南。

啟用 Apple 作為登錄提供商

  1. 火力地堡控制台,打開驗證部分。在登錄方法選項卡,使蘋果的供應商。
  2. 配置 Apple 登錄提供商設置:
    1. 如果您僅在 Apple 平台上部署您的應用程序,您可以將服務 ID、Apple 團隊 ID、私鑰和密鑰 ID 字段留空。
    2. 對於 Android 設備的支持:
      1. 添加火力地堡到您的Android項目。在 Firebase 控制台中設置應用時,請務必註冊應用的 SHA-1 簽名。
      2. 火力地堡控制台,打開驗證部分。在登錄方法選項卡,使蘋果的供應商。指定您在上一節中創建的服務 ID。此外,在 OAuth 代碼流配置部分,指定您的 Apple Team ID 以及您在上一部分中創建的私鑰和密鑰 ID。

遵守 Apple 匿名數據要求

誰選擇了這個選項拍在與蘋果公司為用戶提供了匿名的數據,包括他們的電子郵件地址,在登錄時的選項,用戶必須與該域的電子郵件地址privaterelay.appleid.com 。當您在您的應用程序中使用 Apple 登錄時,您必須遵守任何適用的開發者政策或 Apple 有關這些匿名 Apple ID 的條款。

這包括在您將任何直接識別個人信息與匿名 Apple ID 關聯之前獲得任何必要的用戶同意。使用 Firebase 身份驗證時,這可能包括以下操作:

  • 將電子郵件地址鏈接到匿名 Apple ID,反之亦然。
  • 將電話號碼與匿名 Apple ID 關聯,反之亦然
  • 將非匿名社交憑據(Facebook、Google 等)鏈接到匿名 Apple ID,反之亦然。

上面的列表並不詳盡。請參閱您的開發者帳戶成員資格部分中的 Apple 開發者計劃許可協議,以確保您的應用符合 Apple 的要求。

進入firebase::auth::Auth

Auth類是所有API調用的網關。
  1. 添加驗證和應用頭文件:
    #include "firebase/app.h"
    #include "firebase/auth.h"
    
  2. 在你的初始化代碼,創建一個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. 獲得firebase::auth::Auth類的firebase::App 。之間存在一個一到一映射AppAuth
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);
    

使用 Firebase SDK 處理登錄流程

使用 Apple 登錄的過程因 Apple 和 Android 平台而異。

在蘋果平台上

通過從您的 C++ 代碼調用的 Apple 登錄 Objective-C SDK,使用 Firebase 對您的用戶進行身份驗證。

  1. 對於每個登錄請求,生成一個隨機字符串——一個“nonce”——你將使用它來確保你獲得的 ID 令牌是專門為響應你的應用程序的身份驗證請求而授予的。這一步對於防止重放攻擊很重要。

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

    您將隨登錄請求發送隨機數的 SHA256 哈希值,Apple 將在響應中原封不動地傳遞該哈希值。 Firebase 通過散列原始隨機數並將其與 Apple 傳遞的值進行比較來驗證響應。

  2. 啟動 Apple 的登錄流程,在您的請求中包括隨機數的 SHA256 哈希值和將處理 Apple 響應的委託類(請參閱下一步):

      - (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 的實現中處理 Apple 的響應。如果登錄成功,請使用 Apple 響應中的 ID 令牌和未散列的隨機數來向 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. 使用生成的令牌字符串和原始隨機數構建 Firebase 憑據並登錄 Firebase。

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::User*> result =
        auth->SignInWithCredential(credential);
    
  5. 同樣的模式可以被使用Reauthenticate可用於檢索需要登錄近期敏感操作的新鮮憑證。

    firebase::Future<firebase::auth::SignInResult> result =
        user->Reauthenticate(credential);
    
  6. 可以使用相同的模式將帳戶與 Apple 登錄相關聯。但是,當現有 Firebase 帳戶已關聯到您嘗試關聯的 Apple 帳戶時,您可能會遇到錯誤。如果發生這種情況未來會返回一個狀態kAuthErrorCredentialAlreadyInUse和的用戶信息對象SignInResult可以包含一個有效的updated_credential 。該證書可用於通過Apple聯帳戶登錄SignInWithCredential無需生成另一個蘋果登錄令牌和隨機數。

    請注意,您必須使用LinkAndRetrieveDataWithCredential此操作包含憑證作為updated_credential是成員SignInResult.UserInfo對象。

    firebase::Future<firebase::auth::SignInResult> link_result =
        auth->current_user()->LinkAndRetrieveDataWithCredential(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()->info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::User*> result = auth->SignInWithCredential(
          link_result.result()->info.updated_credential);
    } else {
      // Another link error occurred.
    }
    

在安卓上

在 Android 上,通過使用 Firebase SDK 將基於網絡的通用 OAuth 登錄集成到您的應用程序中來執行端到端登錄流程,從而使用 Firebase 對您的用戶進行身份驗證。

要使用 Firebase SDK 處理登錄流程,請按以下步驟操作:

  1. 構造一個實例FederatedOAuthProviderData與供應商ID適用於蘋果的配置。

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. 可選:指定其他的OAuth 2.0範圍超出了預設的,你想從身份驗證提供者的要求。

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. 可選:如果您想在英語以外的語言顯示蘋果的登錄畫面中,將locale參數。請參閱登錄與蘋果文檔的支持的語言環境。

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. 配置提供程序數據後,使用它來創建 FederatedOAuthProvider。

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. 使用 Auth 提供程序對象通過 Firebase 進行身份驗證。請注意,與其他 FirebaseAuth 操作不同,這將通過彈出一個 Web 視圖來控制您的 UI,用戶可以在其中輸入其憑據。

    要開始流動的跡象,請致電signInWithProvider

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

    然後,您的應用程序可能會等待或註冊在未來的回調

  6. 同樣的模式可以被用來ReauthenticateWithProvider可用於檢索需要登錄近期敏感操作的新鮮憑證。

    firebase::Future<firebase::auth::SignInResult> result =
      user->ReauthenticateWithProvider(provider_data);
    

    然後,您的應用程序可能會等待或註冊在未來的回調

  7. 而且,您可以使用linkWithCredential()以不同的身份提供商現有賬戶連結。

    請注意,Apple 要求您在將用戶的 Apple 帳戶鏈接到其他數據之前獲得用戶的明確同意。

    例如,要將 Facebook 帳戶鏈接到當前的 Firebase 帳戶,請使用您通過將用戶登錄到 Facebook 獲得的訪問令牌:

    // 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::SignInResult> result =
        auth.getCurrentUser().linkWithCredential(credential);
    

使用 Apple Notes 登錄

與 Firebase Auth 支持的其他提供商不同,Apple 不提供照片 URL。

此外,當用戶選擇不與應用程序,蘋果公司規定一個唯一的電子郵件地址的用戶(形式分享他們的電子郵件xyz@privaterelay.appleid.com ,其股您的應用程序)。如果您配置了私人電子郵件中繼服務,Apple 會將發送到匿名地址的電子郵件轉發到用戶的真實電子郵件地址。

蘋果只股票的用戶信息,如第一次的顯示名稱與應用程序在用戶的跡象。通常情況下,火力地堡商店的顯示名稱的第一次用戶登錄在與蘋果,你可以得到getCurrentUser().getDisplayName()但是,如果您之前使用 Apple 登錄用戶而不使用 Firebase,Apple 將不會向 Firebase 提供用戶的顯示名稱。

下一步

用戶首次登錄後,將創建一個新用戶帳戶並將其鏈接到用戶登錄時使用的憑據(即用戶名和密碼、電話號碼或身份驗證提供商信息)。這個新帳戶作為 Firebase 項目的一部分存儲,可用於識別項目中每個應用中的用戶,無論用戶如何登錄。

在您的應用中,您可以從 firebase::auth::user 對象獲取用戶的基本個人資料信息。請參閱管理用戶

在您的 Firebase 實時數據庫和雲存儲安全規則中,您可以從 auth 變量中獲取登錄用戶的唯一用戶 ID,並使用它來控制用戶可以訪問哪些數據。