Google 致力于为黑人社区推动种族平等。查看具体举措
此页面由 Cloud Translation API 翻译。
Switch to English

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

您可以使用Firebase SDK來執行端到端OAuth 2.0登錄流程,從而使用戶使用其Apple ID通過Firebase進行身份驗證。

在你開始之前

要使用Apple登錄用戶,請首先在Apple的開發人員站點上配置“使用Apple登錄”,然後將Apple啟用為Firebase項目的登錄提供程序。

加入蘋果開發者計劃

使用Apple登錄只能由Apple Developer Program的成員配置。

使用Apple配置登錄

必須在Firebase項目中啟用並正確配置Apple登錄。跨Android和iOS平台的配置有所不同。在繼續之前,請先遵循iOS和/或Android指南中的“使用Apple配置登錄”部分。

使Apple成為登錄提供商

  1. Firebase控制台中 ,打開“ 身份驗證”部分。在“ 登錄方法”選項卡上,啟用Apple提供程序。
  2. 配置Apple登錄提供程序設置:
    1. 如果僅在iOS上部署應用程序,則可以將服務ID,Apple Team ID,私鑰和密鑰ID字段保留為空。
    2. 對於Android設備的支持:
      1. 將Firebase添加到您的Android項目 。在Firebase控制台中設置應用程序時,請確保註冊應用程序的SHA-1簽名。
      2. Firebase控制台中 ,打開“ 身份驗證”部分。在“ 登錄方法”選項卡上,啟用Apple提供程序。指定您在上一節中創建的服務ID。另外,在OAuth代碼流配置部分中,指定您的Apple Team ID以及您在上一部分中創建的私鑰和密鑰ID。

符合Apple匿名數據要求

使用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. 添加Auth和App頭文件:
    #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::App獲取firebase::auth::Auth類。 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。

    第45節
  5. 同樣的模式可以被使用Reauthenticate可用於檢索需要登錄近期敏感操作的新鮮憑證。

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

    請注意,您必須使用LinkAndRetrieveDataWithCredential來使此操作包含憑據,因為updated_credentialSignInResult.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上

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

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

  1. 構造一個FederatedOAuthProviderData的實例,該實例配置有適用於Apple的提供者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. 可選:如果要以英語以外的其他語言顯示Apple的登錄屏幕,請設置locale參數。有關受支持的語言環境,請參閱“ 使用Apple登錄”

    // 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);
    

    然後,您的應用程序可以等待或在Future上註冊回調

  6. ReauthenticateWithProvider可以使用相同的模式,該模式可以用於檢索需要最近登錄的敏感操作的新憑據。

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

    然後,您的應用程序可以等待或在Future上註冊回調

  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。

另外,當用戶選擇不與應用程序共享電子郵件時,Apple會為該用戶提供一個唯一的電子郵件地址(格式為xyz@privaterelay.appleid.com ),並與您的應用程序共享。如果您配置了私人電子郵件中繼服務,則Apple會將發送到匿名地址的電子郵件轉發到用戶的真實電子郵件地址。

Apple僅在用戶首次登錄時與應用程序共享用戶信息,例如顯示名稱。通常,Firebase會存儲用戶首次登錄Apple時的顯示名稱,您可以通過getCurrentUser().getDisplayName() 。但是,如果您以前使用Apple在不使用Firebase的情況下將用戶登錄到該應用程序,則Apple將不會向Firebase提供用戶的顯示名稱。

下一步

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

在您的應用中,您可以從firebase :: auth :: user對像中獲取用戶的基本配置文件信息。請參閱管理用戶

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