在 Web 應用程式中使用 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 添加到您的 JavaScript 項目

  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 JavaScript SDK 處理登錄流程,請執行以下步驟:

  1. 使用您在 Firebase 控制台中獲得的提供商 ID 創建OAuthProvider的實例。

    網絡模塊化 API

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('oidc.example-provider');
    

    Web 命名空間 API

    var provider = new firebase.auth.OAuthProvider('oidc.example-provider');
    
  2. 可選:指定要與 OAuth 請求一起發送的其他自定義 OAuth 參數。

    網絡模塊化 API

    provider.setCustomParameters({
      // Target specific email with login hint.
      login_hint: 'user@example.com'
    });
    

    Web 命名空間 API

    provider.setCustomParameters({
      // Target specific email with login hint.
      login_hint: 'user@example.com'
    });
    

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

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

    網絡模塊化 API

    provider.addScope('mail.read');
    provider.addScope('calendars.read');
    

    Web 命名空間 API

    provider.addScope('mail.read');
    provider.addScope('calendars.read');
    

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

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

    您可以將用戶重定向到提供商的登錄頁面或在彈出式瀏覽器窗口中打開登錄頁面。

    重定向流

    通過調用signInWithRedirect()重定向到提供商登錄頁面:

    網絡模塊化 API

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);
    

    Web 命名空間 API

    firebase.auth().signInWithRedirect(provider);
    

    用戶完成登錄返回您的應用後,您可以通過調用getRedirectResult()獲取登錄結果。

    網絡模塊化 API

    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.
    
        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    

    Web 命名空間 API

    firebase.auth().getRedirectResult()
      .then((result) => {
        // IdP data available in result.additionalUserInfo.profile.
        // ...
    
        /** @type {firebase.auth.OAuthCredential} */
        var credential = result.credential;
    
        // OAuth access and id tokens can also be retrieved:
        var accessToken = credential.accessToken;
        var idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    

    彈窗流

    網絡模塊化 API

    import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    signInWithPopup(auth, provider)
      .then((result) => {
        // User is signed in.
        // IdP data available using getAdditionalUserInfo(result)
    
        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    

    Web 命名空間 API

    firebase.auth().signInWithPopup(provider)
      .then((result) => {
        // IdP data available in result.additionalUserInfo.profile.
        // ...
    
        /** @type {firebase.auth.OAuthCredential} */
        var credential = result.credential;
    
        // OAuth access and id tokens can also be retrieved:
        var accessToken = credential.accessToken;
        var idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    
  5. 雖然上述示例側重於登錄流程,但您可以使用相同的模式使用linkWithRedirect()linkWithPopup()將 OIDC 提供商鏈接到現有用戶,並使用reauthenticateWithRedirect()reauthenticateWithPopup()重新驗證用戶,可用於為需要最近登錄的敏感操作檢索新憑據。

手動處理登錄流程

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

網絡模塊化 API

import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";

const provider = new OAuthProvider("oidc.example-provider");
const credential = provider.credential({
    idToken: idToken,
});
signInWithCredential(getAuth(), credential)
    .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.

        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
    })
    .catch((error) => {
        // Handle error.
    });

Web 命名空間 API

const provider = new OAuthProvider("oidc.example-provider");
const credential = provider.credential({
    idToken: idToken,
});
firebase.auth().signInWithCredential(credential)
    .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.

        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
    })
    .catch((error) => {
        // Handle error.
    });