本文件說明在封鎖第三方 Cookie 的瀏覽器中,使用重新導向登入功能的最佳做法。您必須採用本文列出的其中一個選項,signInWithRedirect()
才能在正式環境中透過任何瀏覽器正常運作。
總覽
為了讓您和使用者都能順暢使用 signInWithRedirect()
資料流,Firebase 驗證 JavaScript SDK 會使用與應用程式 Firebase 託管網域連線的跨來源 iframe。不過,這項機制並不適用於封鎖第三方儲存空間存取的瀏覽器。
由於要求使用者停用瀏覽器的儲存空間分區功能,這種情況很少見,因此建議您根據用途的特定用途,為應用程式套用下列其中一種設定選項。
- 如果您是在
firebaseapp.com
的子網域使用 Firebase 託管應用程式代管應用程式,則不會受到這項問題影響,因此無須採取任何行動。 - 如果您是透過自訂網域或
web.app
的子網域使用 Firebase 託管應用程式,請使用選項 1。 - 如果您使用 Firebase 以外的服務託管應用程式,請使用選項 2、選項 3、選項 4 或選項 5。
方法 1:更新 Firebase 設定,將自訂網域設為authDomain
如果您使用自訂網域在 Firebase 託管中託管應用程式,可以設定 Firebase SDK 將自訂網域做為 authDomain
。這可確保應用程式和驗證 iframe 使用相同的網域,避免登入問題。(如果您沒有使用 Firebase 託管,就需要使用其他選項)。確認您已在要用於驗證的專案中設定自訂網域。
如要更新 Firebase 設定,將自訂網域做為驗證網域,請按照下列步驟操作:
將 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>" };
將新的
authDomain
新增到 OAuth 供應商的授權重新導向 URI 清單中。操作方式會因提供者而異,但一般來說,您可以按照任何供應商的「事前準備」部分取得操作說明 (例如 Facebook 供應商)。要授權的已更新 URI 看起來會類似於https://<the-domain-that-serves-your-app>/__/auth/handler
,結尾的/__/auth/handler
非常重要。同樣地,如果您使用 SAML 提供者,請將新的
authDomain
新增至 SAML 宣告客戶服務 (ACS) 網址。確認
continue_uri
已列入授權網域清單。如有需要,請透過 Firebase 託管重新部署
/__/firebase/init.json
託管的最新 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());
網路命名空間 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:透過 Proxy 將驗證要求傳送至 firebaseapp.com
signInWithRedirect
流程一開始會從您的應用程式網域重新導向至 Firebase 設定中 authDomain
參數中指定的網域 (預設為「authDomain
代管登入輔助程式程式碼,後者會重新導向至識別資訊提供者,然後在成功後重新導向回應用程式網域。
驗證流程返回應用程式網域時,會存取登入輔助網域的瀏覽器儲存空間。這個選項和以下做法 (用來自行託管程式碼) 會消除跨來源儲存空間存取權,否則會遭到瀏覽器封鎖。
在應用程式伺服器上設定反向 Proxy,以便將傳送到
https://<app domain>/__/auth/
的 GET/POST 要求轉送至https://<project>.firebaseapp.com/__/auth/
。請確定瀏覽器公開透明,這無法透過 302 重新導向進行。如果您使用 nginx 提供自訂網域,反向 Proxy 設定會如下所示:
# reverse proxy for signin-helpers for popup/redirect sign in. location /__/auth { proxy_pass https://<project>.firebaseapp.com; }
按照選項 1 中的步驟更新已授權的
redirect_uri
、ACS 網址和authDomain
。重新部署應用程式後,就應該不會再出現跨來源儲存空間存取權。
方法 4:自行託管網域中的登入輔助程式碼
另一種消除跨來源儲存空間存取權的方法,是自行託管 Firebase 登入輔助程式碼。不過,這個方法不適用於 Apple 登入或 SAML。請僅在無法採用選項 3 的反向 Proxy 設定的情況下,才使用這個選項。
代管輔助程式碼的步驟如下:
執行下列指令,從
<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
請在您的應用程式網域下代管上述檔案。確認網路伺服器可以回應
https://<app domain>/__/auth/<filename>
和https://<app domain>/__/firebase/init.json
。以下是下載及代管檔案的伺服器實作範例。 建議您定期下載並同步處理檔案,確保獲得最新的錯誤修正及功能。
按照選項 1 中的步驟更新已授權的
redirect_uri
和authDomain
。重新部署應用程式後,就應該不會再出現跨來源儲存空間存取權。
選項 5:獨立處理供應商登入作業
Firebase 驗證 SDK 提供 signInWithPopup()
和 signInWithRedirect()
做為包裝複雜邏輯的便利方法,讓您不必使用其他 SDK。如要完全避免使用上述任一方法,您可以單獨登入供應商,然後使用 signInWithCredential()
交換 Firebase 驗證憑證的供應商憑證。舉例來說,您可以使用 Google 登入 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);
網路命名空間 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 憑證,請參閱這裡的操作說明。