4

我正在构建一个使用 Express 处理服务器请求的同构 React 应用程序。

在客户端运行捆绑的 React 应用程序时,我的 Firebase 登录流程运行良好:

  • 我使用 Firebase 的电子邮件/密码选项登录
  • 认证后,ref.getAuth()成功返回用户的auth对象
  • ref.getAuth()在浏览我的应用程序客户端(通过 react-router)时的后续调用也会返回一个成功的身份验证对象。

但是,即使在客户端成功登录后,硬刷新(来自服务器)也不会持续存在。在服务器上下文中使用相同的 React 组件,ref.getAuth()返回 null。

我是否错过了以与在客户端上工作相同的方式在服务器上工作的步骤(用例是网站的硬刷新)?

4

1 回答 1

8

如果您作为同构/通用渲染的一部分(我假设您是)连接到服务器上的 Firebase,则 Firebase 无法知道哪个用户向您的服务器发起了请求,然后随后向 Firebase 发出了请求——on在客户端,用户的 cookie 可以一起发送到 Firebase,但在服务器上发起请求的是您的服务器,而不是客户端,因此与任何给定用户无关。

我的第一个想法是,为了从服务器发送身份验证,您需要在自己的服务器上进行某种登录;一旦您验证(使用 Firebase 或其他方式)用户就是他们所说的身份,您可以生成一个令牌,您可以(安全地)保存在用户的会话中并发送回客户端。然后,在客户端每个服务器请求上,就在使用 渲染您的 React 应用程序之前React.render*,您将authWithCustomToken()使用该用户的令牌进行调用。

然而,需要注意的是,对 Firebase 数据库的身份验证是全局性的——当您对 Firebase ref 进行身份验证时(即使在 Node.js 中),指向同一数据库的每个其他 ref 都会使用这些凭据进行身份验证;您不能使用单独的参考作为不同的用户登录。因此,如果您在服务器上的 React 渲染管道在调用 auth 回调和渲染应用程序之间执行任何异步操作(例如,如果您使用react-async 之类的东西或在渲染之前执行其他花哨的异步数据加载),用户在您渲染应用程序时,已针对您的 Firebase 进行身份验证可能已更改。但是,如果您的渲染管道是纯同步的,您应该能够摆脱这种策略(getAuth()可以帮助确保您在渲染之前拥有正确的身份验证)。

除此之外,我认为最直接的解决方案如下:

  1. 通过您自己的服务器对您的用户进行身份验证,创建一个安全令牌并将其传递回客户端以进行身份​​验证。将此令牌存储在用户的会话中,以便客户端可以请求它并根据需要在客户端上对其进行身份验证。您还需要生成自己的身份验证数据(通常传递给回调的内容authWithPassword)并将其存储在会话中。

  2. 对于对 Firebase 的服务器请求,请使用推荐的服务器身份验证方案之一:

    使用 Firebase 应用密码:所有身份验证方法都可以接受 Firebase 应用密码,而不是 JWT 令牌。这将授予服务器对整个 Firebase 数据库的完全读写访问权限。除非通过 App Dashboard 撤销此访问权限,否则此访问权限将永不过期。

    使用将可选admin声明设置为的安全 JWT true此方法将授予服务器对整个 Firebase 数据库的完全读写访问权限。此令牌将正常过期,因此相应地设置过期时间很重要。

    使用旨在仅访问服务器需要访问的数据片段的安全 JWT:此方法更复杂,但它是验证服务器的最安全方法,因为它允许安全性和 Firebase 规则阻止服务器执行任何操作它不应该,即使它以某种方式受到损害。

  3. 包括服务器逻辑以确保当前登录的用户只能访问适当的数据。由于上述身份验证方法将授予对用户可能有权访问或无权访问的数据的访问权限,因此您需要采取自己的步骤来确保用户不会意外访问他们不应该访问的内容。

  4. 将您在第一步中存储在会话中的身份验证数据作为属性传递给 React 应用程序,而不是依赖于ref.getAuth()在您的 React 应用程序中获取此数据(因为它在服务器上不起作用)之类的东西,以识别用户界面中的用户。

于 2015-08-16T03:47:29.857 回答