使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

在阻止第三方存储空间访问的浏览器上使用 signInWithRedirect 的最佳做法

本文档介绍了在阻止第三方 Cookie 的浏览器上使用重定向登录的最佳实践。

概览

为了使您和您的用户顺利执行 signInWithRedirect() 流程,Firebase Authentication JavaScript SDK 会使用连接到应用的 Firebase Hosting 网域的跨源 iframe。 但是,此机制不适用于阻止第三方访问存储空间的浏览器。

由于让用户不太可能停用浏览器上的存储分区功能,因此您不太可能选择该选项,而应根据具体用例,将以下设置选项应用到您的应用。

  • 如果您使用 Firebase Hosting 在 firebaseapp.com 的子网域上托管应用,将不会受到此问题的影响,无需执行任何操作。
  • 如果您在自定义网域或 web.app 的子网域上使用 Firebase Hosting 托管应用,请使用方法 1
  • 如果您使用 Firebase 以外的服务托管应用,请使用选项 2选项 3选项 4选项 5

方法 1:更新您的 Firebase 配置,以将您的自定义网域用作 authDomain

如果您使用 Firebase Hosting 在自定义网域上托管应用,则可以配置 Firebase SDK 以使用自定义网域作为 authDomain。这可确保应用和身份验证 iframe 使用相同的网域,从而防止出现登录问题。(如果您不使用 Firebase Hosting,则需要使用其他选项。)

如需更新 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) 网址。

方法 2:切换到 signInWithPopup()

使用 signInWithPopup(),而不要使用 signInWithRedirect()。应用代码的其余部分保持不变,但 UserCredential 对象的检索方式不同。

Web 版本 9

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

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

Web 版本 8

  // 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 网址和 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. 将上述文件托管在应用网域下。确保您的网络服务器可以响应 https://<app domain>/__/auth/<filename>

    此处提供了一个下载和托管文件的服务器实现示例

  3. 按照方法 1 中的步骤更新已获授权的 redirect_uri 和您的 authDomain。重新部署应用后,应该就不会再发生跨源访问存储空间的现象。

选项 5:单独处理提供方登录

Firebase Authentication SDK 提供了两种便捷的方法 signInWithPopup()signInWithRedirect() 来封装复杂的逻辑并避免涉及其他 SDK。您也可以不使用这两种方法,而是独立登录到提供方服务,然后通过 signInWithCredential() 使用提供方的凭据换取 Firebase Authentication 凭据。例如,您可以运行以下代码,使用 Google 登录 SDK示例代码来获取 Google 帐号凭据,然后将新的 Google 凭据实例化:

Web 版本 9

  // `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 版本 8

  // `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 凭据,请点击此处