本文說明在封鎖第三方 Cookie 的瀏覽器上,使用重新導向登入的最佳做法。您必須採取下列其中一種做法,才能確保 signInWithRedirect() 在所有瀏覽器的正式環境中正常運作。
總覽
為確保您和使用者都能順暢完成signInWithRedirect()流程,Firebase 驗證 JavaScript SDK 會使用跨來源 iframe,連線至應用程式的 Firebase 託管網域。不過,如果瀏覽器會封鎖第三方儲存空間存取權,這個機制就無法運作。
要求使用者在瀏覽器上停用儲存空間分割功能並非易事,因此請根據您的用途,為應用程式套用下列其中一種設定選項。
- 如果您在
firebaseapp.com的子網域上使用 Firebase 託管代管應用程式,就不會受到這個問題影響,因此不必採取任何行動。 - 如果您使用 Firebase 託管 在自訂網域或
web.app的子網域上代管應用程式,請使用選項 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 物件的擷取方式不同。
Web
// Before
// ==============
signInWithRedirect(auth, new GoogleAuthProvider());
// After the page redirects back
const userCred = await getRedirectResult(auth);
// After
// ==============
const userCred = await signInWithPopup(auth, new GoogleAuthProvider());
Web
// 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/__/auth/links wget https://<project>.firebaseapp.com/__/auth/links.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 憑證:
Web
// `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
// `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 憑證的操作說明,請參閱這篇文章。