在阻止第三方儲存存取的瀏覽器上使用 signInWithRedirect 的最佳實踐

本文檔介紹了在封鎖第三方 cookie 的瀏覽器上使用重定向登入的最佳實務。您必須遵循此處列出的選項之一, signInWithRedirect()才能在所有瀏覽器中的生產環境中按預期運行。

概述

為了讓您和您的使用者能夠無縫地執行signInWithRedirect()流程,Firebase 驗證 JavaScript SDK 使用連接到您應用的 Firebase 託管網域的跨來源 iframe。但是,此機制不適用於阻止第三方儲存存取的瀏覽器。

由於要求使用者停用瀏覽器上的儲存分區功能很少是一種選擇,因此您應該根據用例的具體情況,將以下設定選項之一應用於您的應用程式。

  • 如果您使用 Firebase Hosting 在firebaseapp.com的子網域上託管應用程序,則您不會受到此問題的影響,無需採取任何措施。
  • 如果您使用 Firebase Hosting 在自訂網域或web.app的子網域上託管應用程序,請使用選項 1
  • 如果您使用 Firebase 以外的服務託管應用,請使用Option 2Option 3Option 4Option 5

選項 1:更新您的 Firebase 配置以使用自訂網域作為authDomain

如果您使用自訂網域透過 Firebase Hosting 來託管您的應用程式,則可以將 Firebase SDK 設定為使用您的自訂網域作為authDomain 。這可確保您的應用程式和身份驗證 iframe 使用相同的網域,從而防止登入問題。 (如果您不使用 Firebase 託管,則需要使用其他選項。)

若要更新您的 Firebase 設定以使用自訂網域作為驗證網域,請執行下列操作:

  1. 配置 Firebase JS SDK 以使用您的自訂網域作為authDomain

    const firebaseConfig = {
      apiKey: "<api-key>",
      authDomain: "<the-domain-that-serves-your-app>",
      databaseURL: "<database-url>",
      projectId: "<project-id>",
      appId: "<app-id>"
    };
    
  2. 將新的authDomain新增至 OAuth 提供者的授權重定向 URI 清單中。如何執行此操作取決於提供者,但一般來說,您可以按照任何提供者(例如Facebook 提供者)中的「開始之前」部分來取得準確說明。更新後的授權 URI 看起來像https://<the-domain-that-serves-your-app>/__/auth/handler — 結尾的/__/auth/handler很重要。

    同樣,如果您使用 SAML 提供程序,請將新的authDomain新增至 SAML 斷言消費者服務 (ACS) URL。

  3. 確保您的continue_uri位於授權網域清單中。

  4. 如果需要取得託管在/__/firebase/init.json的最新 Firebase 設定文件,請使用 Firebase 託管重新部署。

選項 2:切換到signInWithPopup()

使用signInWithPopup()而不是signInWithRedirect() 。應用程式程式碼的其餘部分保持不變,但 UserCredential 物件的擷取方式有所不同。

網路模組化API

  // Before
  // ==============
  signInWithRedirect(auth, new GoogleAuthProvider());
  // After the page redirects back
  const userCred = await getRedirectResult(auth);

  // After
  // ==============
  const userCred = await signInWithPopup(auth, new GoogleAuthProvider());

Web 命名空間 API

  // Before
  // ==============
  firebase.auth().signInWithRedirect(new firebase.auth.GoogleAuthProvider());
  // After the page redirects back
  var userCred = await firebase.auth().getRedirectResult();

  // After
  // ==============
  var userCred = await firebase.auth().signInWithPopup(
      new firebase.auth.GoogleAuthProvider());
```

彈出視窗登入並不總是適合用戶 - 彈出視窗有時會被裝置或平台阻止,並且行動用戶的流程不太順暢。如果您的應用程式存在使用彈出視窗的問題,則您需要遵循其他選項之一。

選項 3:將身份驗證請求代理到 firebaseapp.com

signInWithRedirect流程首先從您的應用程式網域重新導向到 firebase 設定中的authDomain參數中指定的網域(“ .firebaseapp.com」預設) authDomain託管重定向到身分提供者的登入幫助程式程式碼,成功後,身分提供者將重定向回應用程式網域。

當身份驗證流程返回您的應用程式網域時,將存取登入幫助程式網域的瀏覽器儲存。此選項和以下選項(自行託管程式碼)消除了跨來源儲存訪問,否則會被瀏覽器阻止。

  1. 在應用程式伺服器上設定反向代理,以便將對https://<app domain>/__/auth/ GET/POST 請求轉送至https://<project>.firebaseapp.com/__/auth/ 。確保此轉發對於瀏覽器是透明的;這不能透過 302 重定向來完成。

    如果您使用 nginx 來服務您的自訂網域,則反向代理程式配置將如下所示:

    # reverse proxy for signin-helpers for popup/redirect sign in.
    location /__/auth {
      proxy_pass https://<project>.firebaseapp.com;
    }
    
  2. 請依照選項 1中的步驟更新授權的redirect_uri 、 ACS URL 和您的authDomain 。重新部署應用程式後,跨網域儲存存取權應該不再發生。

選項 4:在您的網域中自行託管登入說明程式碼

消除跨網域儲存存取的另一種方法是自行託管 Firebase 登入幫助程式程式碼。但是,此方法不適用於 Apple 登入或 SAML。僅當選項 3 中的反向代理設定不可行時才使用此選項。

託管幫助程式碼有以下步驟:

  1. 透過執行以下命令,從<project>.firebaseapp.com位置下載要託管的檔案:

    mkdir signin_helpers/ && cd signin_helpers
    wget https://<project>.firebaseapp.com/__/auth/handler
    wget https://<project>.firebaseapp.com/__/auth/handler.js
    wget https://<project>.firebaseapp.com/__/auth/experiments.js
    wget https://<project>.firebaseapp.com/__/auth/iframe
    wget https://<project>.firebaseapp.com/__/auth/iframe.js
    wget https://<project>.firebaseapp.com/__/firebase/init.json
    
  2. 將上述文件託管在您的應用程式網域下。確保您的 Web 伺服器可以回應https://<app domain>/__/auth/<filename>https://<app domain>/__/firebase/init.json

    以下是下載和託管文件的範例伺服器實作。我們建議定期下載和同步文件,以確保獲取最新的錯誤修復和功能。

  3. 請依照選項 1中的步驟更新授權的redirect_uri和您的authDomain 。重新部署應用程式後,跨網域儲存存取權應該不再發生。

選項 5:獨立處理提供者登入

Firebase Authentication SDK 提供了signInWithPopup()signInWithRedirect()作為封裝複雜邏輯的便利方法,並避免需要涉及另一個SDK。您可以完全避免使用任何一種方法,方法是獨立登入您的提供者,然後使用signInWithCredential()將提供者的憑證交換為 Firebase 驗證憑證。例如,您可以使用Google Sign In SDK範例程式碼取得 Google 帳戶憑證,然後透過執行下列程式碼實例化新的 Google 憑證:

網路模組化API

  // `googleUser` from the onsuccess Google Sign In callback.
  //  googUser = gapi.auth2.getAuthInstance().currentUser.get();
  const credential = GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token);
  const result = await signInWithCredential(auth, credential);

Web 命名空間 API

  // `googleUser` from the onsuccess Google Sign In callback.
  const credential = firebase.auth.GoogleAuthProvider.credential(
      googleUser.getAuthResponse().id_token);
  const result = await firebase.auth().signInWithCredential(credential);

呼叫signInWithCredential()後,應用程式的其餘部分的功能與之前相同。

有關取得 Apple 憑證的說明,請參閱此處