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

本文檔介紹了在阻止第三方 cookie 的瀏覽器上使用重定向登錄的最佳做法。您必須遵循此處列出的選項之一,以便signInWithRedirect()在所有瀏覽器的生產環境中按預期運行。

概述

為了讓您和您的用戶無縫地使用signInWithRedirect()流程,Firebase 身份驗證 JavaScript SDK 使用連接到您應用的 Firebase 託管域的跨源 iframe。但是,此機制不適用於阻止第三方存儲訪問的瀏覽器。

因為要求您的用戶在瀏覽器上禁用存儲分區功能很少是一種選擇,所以您應該根據您的用例的具體情況,將以下設置選項之一應用於您的應用程序。

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

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

如果您使用自定義域通過 Firebase 託管託管您的應用,則可以配置 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。

選項 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
    
  2. 在您的應用程序域下託管上述文件。確保您的 Web 服務器可以響應https://<app domain>/__/auth/<filename>

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

  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 憑據的說明在此處