Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

在 Android 上使用 OpenID Connect 進行身份驗證

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

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

在你開始之前

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

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

  • 客戶端密碼:提供者用來確認客戶端 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 添加到您的 Android 項目中。

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

  3. 在 Firebase 控制台的登錄提供程序頁面上,單擊添加新提供程序,然後單擊OpenID Connect

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

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

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

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

  7. 保存您的更改。

使用 Firebase SDK 處理登錄流程

如果您正在構建 Android 應用,使用您的 OIDC 提供程序通過 Firebase 對您的用戶進行身份驗證的最簡單方法是使用 Firebase Android SDK 處理整個登錄流程。

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

  1. 使用它的Builder和提供者的 ID 構造一個OAuthProvider的實例

    Kotlin+KTX

    val providerBuilder = OAuthProvider.newBuilder("oidc.example-provider")
    

    Java

    OAuthProvider.Builder providerBuilder = OAuthProvider.newBuilder("oidc.example-provider");
    
  2. 可選:指定要隨 OAuth 請求一起發送的其他自定義 OAuth 參數。

    Kotlin+KTX

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com")
    

    Java

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com");
    

    請諮詢您的 OIDC 提供商以了解他們支持的參數。請注意,您不能使用setCustomParameters()傳遞 Firebase 所需的參數。這些參數是client_idresponse_typeredirect_uristatescoperesponse_mode

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

    Kotlin+KTX

    val scopes = arrayListOf("mail.read", "calendars.read")
    providerBuilder.setScopes(scopes)
    

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("mail.read");
            add("calendars.read");
          }
        };
    providerBuilder.setScopes(scopes);
    

    請諮詢您的 OIDC 提供商以了解他們使用的範圍。

  4. 使用 OAuth 提供程序對象向 Firebase 進行身份驗證。請注意,與其他 FirebaseAuth 操作不同,這將通過彈出Custom Chrome Tab來控制您的 UI。因此,不要在您附加的OnSuccessListenerOnFailureListener中引用您的 Activity,因為它們會在操作啟動 UI 時立即分離。

    您應該首先檢查您是否已經收到回复。使用此方法登錄會將您的 Activity 置於後台,這意味著它可以在登錄流程中被系統回收。為了確保在發生這種情況時不會讓用戶重試,您應該檢查結果是否已經存在。

    要檢查是否有待處理的結果,請調用getPendingAuthResult

    Kotlin+KTX

    val pendingResultTask = FirebaseAuth.getInstance().pendingAuthResult
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
            .addOnSuccessListener { authResult ->
                // User is signed in.
    
                // IdP data available in
                //   authResult.additionalUserInfo.profile
    
                // The OAuth access token and ID token can also be retrieved:
                val credential = authResult.credential
                if (credential !is OAuthCredential)
                    return@addOnSuccessListener
                val accessToken = credential.accessToken
                val idToken = credential.idToken
            }
            .addOnFailureListener { e ->
                // Handle failure.
            }
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }
    

    Java

    Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
    if (pendingResultTask != null) {
      // There's something already here! Finish the sign-in for your user.
      pendingResultTask
          .addOnSuccessListener(
              new OnSuccessListener<AuthResult>() {
                @Override
                public void onSuccess(AuthResult authResult) {
                  // User is signed in.
                  // IdP data available in
                  // authResult.getAdditionalUserInfo().getProfile().
                  // The OAuth access token can also be retrieved:
                  // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                  // The OAuth ID token can also be retrieved:
                  // ((OAuthCredential)authResult.getCredential()).getIdToken().
                }
              })
          .addOnFailureListener(
              new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                  // Handle failure.
                }
              });
    } else {
      // There's no pending result so you need to start the sign-in flow.
      // See below.
    }
    

    要啟動登錄流程,請調用startActivityForSignInWithProvider

    Kotlin+KTX

    FirebaseAuth.getInstance()
        .startActivityForSignInWithProvider(/* activity= */ this, providerBuilder.build())
        .addOnSuccessListener { authResult ->
            // User is signed in.
    
            // IdP data available in:
            //    authResult.additionalUserInfo.profile
    
            // The OAuth access token and ID token can also be retrieved:
            val credential = authResult.credential
            if (credential !is OAuthCredential)
                return@addOnSuccessListener
            val accessToken = credential.accessToken
            val idToken = credential.idToken
        }
        .addOnFailureListener { e ->
            // Handle failure.
        }
    

    Java

    firebaseAuth
        .startActivityForSignInWithProvider(/* activity= */ this, providerBuilder.build())
        .addOnSuccessListener(
            new OnSuccessListener<AuthResult>() {
              @Override
              public void onSuccess(AuthResult authResult) {
                // User is signed in.
                // IdP data available in
                // authResult.getAdditionalUserInfo().getProfile().
                // The OAuth access token can also be retrieved:
                // authResult.getCredential().getAccessToken().
                // The OAuth ID token can also be retrieved:
                // authResult.getCredential().getIdToken().
              }
            })
        .addOnFailureListener(
            new OnFailureListener() {
              @Override
              public void onFailure(@NonNull Exception e) {
                // Handle failure.
              }
            });
    
  5. 雖然上述示例側重於登錄流程,但您還可以使用startActivityForLinkWithProvider將 OIDC 提供程序鏈接到現有用戶。例如,您可以將多個提供商鏈接到同一個用戶,允許他們使用其中任何一個登錄。

    Kotlin+KTX

    // The user is already signed-in.
    val firebaseUser = FirebaseAuth.getInstance().currentUser
    
    firebaseUser
        ?.startActivityForLinkWithProvider(/* activity= */ this, providerBuilder.build())
        ?.addOnSuccessListener { authResult ->
            // OIDC credential is linked to the current user.
    
            // IdP data available in:
            //   authResult.additionalUserInfo.profile
    
            // The OAuth access token and ID token can also be retrieved:
            val credential = authResult.credential
            if (credential !is OAuthCredential)
                return@addOnSuccessListener
            val accessToken = credential.accessToken
            val idToken = credential.idToken
        }
        ?.addOnFailureListener { e ->
            // Handle failure.
        }
    

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
        .startActivityForLinkWithProvider(/* activity= */ this, provider.build())
        .addOnSuccessListener(
            new OnSuccessListener<AuthResult>() {
              @Override
              public void onSuccess(AuthResult authResult) {
                // Credential is linked to the current user.
                // IdP data available in
                // authResult.getAdditionalUserInfo().getProfile().
                // The OAuth access token can also be retrieved:
                // authResult.getCredential().getAccessToken().
                // The OAuth ID token can also be retrieved:
                // authResult.getCredential().getIdToken().
              }
            })
        .addOnFailureListener(
            new OnFailureListener() {
              @Override
              public void onFailure(@NonNull Exception e) {
                // Handle failure.
              }
            });
    
  6. startActivityForReauthenticateWithProvider可以使用相同的模式,它可用於檢索需要最近登錄的敏感操作的新憑據。

    Kotlin+KTX

    // The user is already signed-in.
    val firebaseUser = FirebaseAuth.getInstance().currentUser
    
    firebaseUser
        ?.startActivityForReauthenticateWithProvider(/* activity= */ this, providerBuilder.build())
        ?.addOnSuccessListener {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
        }
        ?.addOnFailureListener {
            // Handle failure.
        }
    

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
        .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
        .addOnSuccessListener(
            new OnSuccessListener<AuthResult>() {
              @Override
              public void onSuccess(AuthResult authResult) {
                // User is re-authenticated with fresh tokens and
                // should be able to perform sensitive operations
                // like account deletion and email or password
                // update.
              }
            })
        .addOnFailureListener(
            new OnFailureListener() {
              @Override
              public void onFailure(@NonNull Exception e) {
                // Handle failure.
              }
            });
    

手動處理登錄流程

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

Kotlin+KTX

      val credential = OAuthProvider
          .newCredentialBuilder("oidc.example-provider")  // As registered in Firebase console.
          .setIdToken(idToken)  // ID token from OpenID Connect flow.
          .build()
      FirebaseAuth.getInstance()
          .signInWithCredential(credential)
          .addOnSuccessListener { authResult ->
              // User is signed in.

              // IdP data available in:
              //    authResult.additionalUserInfo.profile
          }
          .addOnFailureListener { e ->
              // Handle failure.
          }

Java

AuthCredential credential = OAuthProvider
        .newCredentialBuilder("oidc.example-provider")  // As registered in Firebase console.
        .setIdToken(idToken)  // ID token from OpenID Connect flow.
        .build();
FirebaseAuth.getInstance()
        .signInWithCredential(credential)
        .addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                // User is signed in.

                // IdP data available in:
                //    authResult.getAdditionalUserInfo().getProfile()
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Handle failure.
            }
        });

下一步

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

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

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

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

要註銷用戶,請調用signOut

Java

FirebaseAuth.getInstance().signOut();

Kotlin+KTX

Firebase.auth.signOut()