在 Apple 平台上使用 OpenID Connect 進行身份驗證

如果您已升級到使用 Identity Platform 進行 Firebase 身份驗證,則可以使用您選擇的兼容 OpenID Connect (OIDC) 的提供商通過 Firebase 對您的用戶進行身份驗證。這使得使用 Firebase 本身不支持的身份提供者成為可能。

在你開始之前

要使用 OIDC 提供商登錄用戶,您必須首先從提供商那裡收集一些信息:

  • Client ID :供應商唯一的字符串,用於標識您的應用程序。您的提供商可能會為您支持的每個平台分配不同的客戶端 ID。這是您的提供商發布的 ID 令牌中aud聲明的值之一。

  • Client secret :提供商用來確認客戶端 ID 所有權的秘密字符串。對於每個客戶端 ID,您都需要一個匹配的客戶端密碼。 (僅當您使用auth code flow時才需要此值,強烈建議這樣做。)

  • Issuer :標識您的提供商的字符串。此值必須是一個 URL,當附加/.well-known/openid-configuration時,它是提供者的 OIDC 發現文檔的位置。例如,如果頒發者是https://auth.example.com ,則發現文檔必須在https://auth.example.com/.well-known/openid-configuration可用。

獲得上述信息後,啟用 OpenID Connect 作為您的 Firebase 項目的登錄提供程序:

  1. 將 Firebase 添加到您的 iOS 項目

  2. 如果您尚未升級到 Firebase Authentication with Identity Platform,請執行此操作。 OpenID Connect 身份驗證僅在升級後的項目中可用。

  3. 在 Firebase 控制台的Sign-in providers頁面上,點擊Add new provider ,然後點擊OpenID Connect

  4. 選擇您將使用授權代碼流還是隱式授權流

    如果您的提供商支持,您應該始終使用代碼流。隱式流不太安全,強烈建議不要使用它。

  5. 給這個提供者一個名字。請注意生成的提供者 ID:類似oidc.example-provider東西。當您將登錄代碼添加到您的應用程序時,您將需要此 ID。

  6. 指定您的客戶端 ID 和客戶端密碼,以及您的提供商的頒發者字符串。這些值必須與您的提供商分配給您的值完全匹配。

  7. 保存您的更改。

使用 Firebase SDK 處理登錄流程

使用 OIDC 提供商通過 Firebase 對用戶進行身份驗證的最簡單方法是使用 Firebase SDK 處理整個登錄流程。

要使用 Firebase Apple 平台 SDK 處理登錄流程,請執行以下步驟:

  1. 將自定義 URL 方案添加到您的 Xcode 項目:

    1. 打開您的項目配置:雙擊左側樹視圖中的項目名稱。從TARGETS部分選擇您的應用程序,然後選擇Info選項卡,並展開URL Types部分。
    2. 單擊+按鈕,並將您的編碼應用程序 ID 添加為 URL 方案。您可以在 Firebase 控制台的常規設置頁面上的 iOS 應用程序部分找到您的編碼應用程序 ID。將其他字段留空。

      完成後,您的配置應類似於以下內容(但具有特定於應用程序的值):

      Xcode自定義URL scheme設置界面截圖
  2. 使用您在 Firebase 控制台中獲得的提供商 ID 創建OAuthProvider的實例。

    迅速

    var provider = OAuthProvider(providerID: "oidc.example-provider")
    

    目標-C

    FIROAuthProvider *provider = [FIROAuthProvider providerWithProviderID:@"oidc.example-provider"];
    
  3. 可選:指定要與 OAuth 請求一起發送的其他自定義 OAuth 參數。

    迅速

    provider.customParameters = [
      "login_hint": "user@example.com"
    ]
    

    目標-C

    [provider setCustomParameters:@{@"login_hint": @"user@example.com"}];
    

    請與您的提供商核實其支持的參數。請注意,您不能使用setCustomParameters傳遞 Firebase 所需的參數。這些參數是client_idresponse_typeredirect_uristatescoperesponse_mode

  4. 可選:指定要從身份驗證提供程序請求的基本配置文件之外的其他 OAuth 2.0 範圍。

    迅速

    provider.scopes = ["mail.read", "calendars.read"]
    

    目標-C

    [provider setScopes:@[@"mail.read", @"calendars.read"]];
    

    請諮詢您的提供商以了解其支持的範圍。

  5. 可選:如果您想自定義您的應用在向用戶顯示 reCAPTCHA 時呈現SFSafariViewControllerUIWebView的方式,請創建一個符合AuthUIDelegate協議的自定義類。

  6. 使用 OAuth 提供程序對象通過 Firebase 進行身份驗證。

    迅速

    // If you created a custom class that conforms to AuthUIDelegate,
    // pass it instead of nil:
    provider.getCredentialWith(nil) { credential, error in
      if error != nil {
        // Handle error.
      }
      if credential != nil {
        Auth().signIn(with: credential) { authResult, error in
          if error != nil {
            // Handle error.
          }
          // User is signed in.
          // IdP data available in authResult.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.accessToken
          // OAuth ID token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.idToken
        }
      }
    }
    

    目標-C

    // If you created a custom class that conforms to AuthUIDelegate,
    // pass it instead of nil:
    [provider getCredentialWithUIDelegate:nil
                                completion:^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
      if (error) {
        // Handle error.
      }
      if (credential) {
        [[FIRAuth auth] signInWithCredential:credential
                                  completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
          if (error) {
            // Handle error.
          }
          // User is signed in.
          // IdP data available in authResult.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // ((FIROAuthCredential *)authResult.credential).accessToken
          // OAuth ID token can also be retrieved:
          // ((FIROAuthCredential *)authResult.credential).idToken
        }];
      }
    }];
    
  7. 雖然上述示例側重於登錄流程,但您也可以使用linkWithCredential將 OIDC 提供商鏈接到現有用戶。例如,您可以將多個提供商鏈接到同一個用戶,允許他們使用其中任何一個登錄。

    迅速

    Auth().currentUser.link(withCredential: credential) { authResult, error in
      if error != nil {
        // Handle error.
      }
      // OIDC credential is linked to the current user.
      // IdP data available in authResult.additionalUserInfo.profile.
      // OAuth access token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.accessToken
      // OAuth ID token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.idToken
    }
    

    目標-C

    [[FIRAuth auth].currentUser
        linkWithCredential:credential
                completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
      if (error) {
        // Handle error.
      }
      // OIDC credential is linked to the current user.
      // IdP data available in authResult.additionalUserInfo.profile.
      // OAuth access token can also be retrieved:
      // ((FIROAuthCredential *)authResult.credential).accessToken
      // OAuth ID token can also be retrieved:
      // ((FIROAuthCredential *)authResult.credential).idToken
    }];
    
  8. 相同的模式可以與reauthenticateWithCredential一起使用,它可用於為需要最近登錄的敏感操作檢索新的憑據。

    迅速

    Auth().currentUser.reauthenticateWithCredential(withCredential: credential) { authResult, error in
      if error != nil {
        // Handle error.
      }
      // User is re-authenticated with fresh tokens minted and
      // should be able to perform sensitive operations like account
      // deletion and email or password update.
      // IdP data available in result.additionalUserInfo.profile.
      // Additional OAuth access token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.accessToken
      // OAuth ID token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.idToken
    }
    

    目標-C

    [[FIRAuth auth].currentUser
        reauthenticateWithCredential:credential
                          completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
      if (error) {
        // Handle error.
      }
      // User is re-authenticated with fresh tokens minted and
      // should be able to perform sensitive operations like account
      // deletion and email or password update.
      // IdP data available in result.additionalUserInfo.profile.
      // Additional OAuth access token can also be retrieved:
      // ((FIROAuthCredential *)authResult.credential).accessToken
      // OAuth ID token can also be retrieved:
      // ((FIROAuthCredential *)authResult.credential).idToken
    }];
    

手動處理登錄流程

如果您已經在應用中實施了 OpenID Connect 登錄流程,則可以直接使用 ID 令牌向 Firebase 進行身份驗證:

迅速

let credential = OAuthProvider.credential(
    withProviderID: "oidc.example-provider",  // As registered in Firebase console.
    idToken: idToken,  // ID token from OpenID Connect flow.
    rawNonce: nil
)
Auth.auth().signIn(with: credential) { authResult, error in
    if error {
        // Handle error.
        return
    }
    // User is signed in.
    // IdP data available in authResult?.additionalUserInfo?.profile
}

目標-C

FIROAuthCredential *credential =
    [FIROAuthProvider credentialWithProviderID:@"oidc.example-provider"  // As registered in Firebase console.
                                       IDToken:idToken  // ID token from OpenID Connect flow.
                                      rawNonce:nil];
[[FIRAuth auth] signInWithCredential:credential
                          completion:^(FIRAuthDataResult * _Nullable authResult,
                                      NSError * _Nullable error) {
    if (error != nil) {
        // Handle error.
        return;
    }
    // User is signed in.
    // IdP data available in authResult.additionalUserInfo.profile
}];

下一步

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

  • 在您的應用程序中,您可以從User對象獲取用戶的基本個人資料信息。請參閱管理用戶

  • 在您的 Firebase Realtime Database 和 Cloud Storage Security Rules中,您可以從auth變量中獲取登錄用戶的唯一用戶 ID,並使用它來控制用戶可以訪問的數據。

您可以允許用戶使用多個身份驗證提供程序登錄您的應用程序,方法是將身份驗證提供程序憑據鏈接到現有用戶帳戶。

要註銷用戶,請調用signOut:

迅速

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

目標-C

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

您可能還想為所有身份驗證錯誤添加錯誤處理代碼。請參閱處理錯誤