Reactjs Firebase身份验证状态在客户端上保持,但在硬刷新时不保持

Reactjs Firebase身份验证状态在客户端上保持,但在硬刷新时不保持,reactjs,firebase,firebase-security,isomorphic-javascript,firebase-authentication,Reactjs,Firebase,Firebase Security,Isomorphic Javascript,Firebase Authentication,我正在构建一个同构的React应用程序,它使用Express来处理服务器请求 在客户端运行捆绑的React应用程序时,我的Firebase登录流运行良好: 我使用Firebase的电子邮件/密码选项登录 身份验证后,ref.getAuth()成功返回用户的身份验证对象 在我的应用程序客户端(通过react路由器)导航时,对ref.getAuth()的后续调用也会返回一个成功的auth对象 但是,即使在成功登录客户端之后,硬刷新(来自服务器)也不会持续。在服务器上下文中使用相同的React组件

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

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

  • 我使用Firebase的电子邮件/密码选项登录
  • 身份验证后,
    ref.getAuth()
    成功返回用户的身份验证对象
  • 在我的应用程序客户端(通过react路由器)导航时,对
    ref.getAuth()
    的后续调用也会返回一个成功的auth对象
但是,即使在成功登录客户端之后,硬刷新(来自服务器)也不会持续。在服务器上下文中使用相同的React组件,
ref.getAuth()
返回null


我是否遗漏了一个步骤,使其在服务器上的工作方式与在客户端上的工作方式相同(用例是站点的硬刷新)?

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

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

然而,需要注意的一点是,对Firebase数据库的身份验证是全局的,当您对Firebase ref进行身份验证时(即使在Node.js中),指向同一数据库的每个其他ref都会使用这些凭据进行身份验证;不能使用单独的引用以不同的用户身份登录。因此,如果服务器上的React呈现管道在调用auth回调和呈现应用程序之间执行任何异步操作(例如,如果在呈现之前使用类似的方式或执行其他奇特的异步数据加载),通过Firebase身份验证的用户在您呈现应用程序时可能已更改。但是,如果渲染管道是完全同步的,则应该可以使用此策略(
getAuth()
可以帮助确保在渲染之前具有正确的身份验证)

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

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

  • 对于Firebase的服务器请求,请使用以下选项之一:

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

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

    使用安全JWT,只允许访问服务器需要接触的数据片段:此方法更复杂,但它是对服务器进行身份验证的最安全的方法,因为它可以防止服务器做任何不应该做的事情,即使它以某种方式受到损害

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

  • 将您在步骤1中存储在会话中的身份验证数据作为属性传递给React应用程序,而不是依靠
    ref.getAuth()
    之类的方法在React应用程序中获取此数据(因为它在服务器上不起作用),以识别UI中的用户


  • 这是一个惊人的答案-谢谢!如果我真的在做一些奇特的异步数据获取(使用react transmit),这整件事会失败吗?@Jon第一个解决方案,附带警告,可能会失败,因为你不能依靠Firebase正确实施你的安全规则,因为第二个请求可能会在异步工作完成之前进入并针对数据库重新身份验证。但是,第二种解决方案,即在您自己的服务器上实现一些安全性(例如,确保用户不请求其无权访问的资源),应该仍然有效,你的意思是在我的Express服务器上或多或少地复制我的FB安全规则吗?我想你是对的a)-即使是一个专用的身份验证服务器也可能无法工作b/c你仍然需要同步调用,这可能会变得很危险。对于b)显然可以将上下文作为第二个参数传递(
    var ref=new Firebase(url,new Firebase.context());
    ,它为每个上下文打开一个单独的套接字。我认为c)是clea