Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

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

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

在你開始之前

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

加入 Apple 開發者計劃

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

配置使用 Apple 登錄

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

啟用 Apple 作為登錄提供商

  1. 火力地堡控制台,打開驗證部分。在登錄方法選項卡,使蘋果的供應商。
  2. 配置 Apple 登錄提供商設置:
    1. 如果您僅在 iOS 上部署您的應用程序,您可以將服務 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 登錄的過程因 iOS 和 Android 平台而異。

在 iOS 上

通過從您的 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,並使用它來控制用戶可以訪問哪些數據。