如何协调 Firebase 身份验证令牌刷新与服务器端渲染

Mik*_*ont 4 firebase firebase-authentication server-side-rendering

我们在工作中的 Next.js 应用中使用 Firebase。我对两者都是新手,但尽了最大努力阅读两者。我的问题更多的是 Firebase,而不是 Next.js。这是上下文:

  • 在客户端应用程序中,我对 API 进行了一些调用,并在标头中传递 JWT(ID 令牌)Authorization。API 调用admin.auth().verifyIdToken以检查 ID 令牌是否足够新鲜。这工作正常,因为我或多或少保证 ID 令牌会定期刷新(通过使用onIDTokenChangeddoc link

  • 现在我希望能够在服务器端渲染我的应用程序页面。为此,我将 ID 令牌存储在服务器可读的 cookie 中。但从现在开始,我不能保证下次用户通过整页加载来加载应用程序时 ID 令牌足够新鲜。

我找不到与onIDTokenChanged.

这篇博文提到了一个用于刷新令牌的google API 端点。我可以从服务器上访问它并给它一个刷新令牌,但感觉就像我完全走出了 Firebase 领域,我担心维护临时系统将成为一种负担。

所以我的问题是,人们通常如何协调 Firebase 身份验证与 SSR?我错过了什么吗?

谢谢你!

小智 6

我最近也遇到了同样的问题,我自己解决了。我创建了一个非常简单的页面,负责强制 firebase 令牌刷新,并将用户重定向回请求的页面。是这样的:

  • 在服务器端,exp从 cookie 中提取令牌值后检查它(如果您在该服务器上使用 firebase-admin,它可能会在验证后告诉您错误)
// Could be a handler like this
const handleTokenCookie = (context) => {
  try {
    const token = parseTokenFromCookie(context.req.headers.cookie)
    await verifyToken(token)
  } catch (err) {
    if (err.name === 'TokenExpired') {
      // If expired, user will be redirected to /refresh page, which will force a client-side
      // token refresh, and then redirect user back to the desired page
      const encodedPath = encodeURIComponent(context.req.url)
      context.res.writeHead(302, {
        // Note that encoding avoids URI problems, and `req.url` will also
        // keep any query params intact
        Location: `/refresh?redirect=${encodedPath}`
      })
      context.res.end()
    } else {
      // Other authorization errors...
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

该处理程序可以在 /pages 上使用,如下所示

// /pages/any-page.js
export async function getServerSideProps (context) {
  const token = await handleTokenCookie(context)
  if (!token) {
    // Token is invalid! User is being redirected to /refresh page
    return {}
  }

  // Your code...
}
Run Code Online (Sandbox Code Playgroud)
  • 现在您需要创建一个简单的/refresh页面,负责在客户端强制刷新 firebase 令牌,并且在更新令牌和 cookie 后,它应该将用户重定向回所需的页面。
// /pages/refresh.js

const Refresh = () => {
  // This hook is something like https://github.com/vercel/next.js/blob/canary/examples/with-firebase-authentication/utils/auth/useUser.js
  const { user } = useUser()
  React.useEffect(function forceTokenRefresh () {
    // You should also handle the case where currentUser is still being loaded

    currentUser
      .getIdToken(true) // true will force token refresh
      .then(() => {
        // Updates user cookie
        setUserCookie(currentUser)

        // Redirect back to where it was
        const decodedPath = window.decodeURIComponent(Router.query.redirect)
        Router.replace(decodedPath)
      })
      .catch(() => {
        // If any error happens on refresh, redirect to home
        Router.replace('/')
      })
  }, [currentUser])

  return (
    // Show a simple loading while refreshing token?
    <LoadingComponent />
  )
}

export default Refresh

Run Code Online (Sandbox Code Playgroud)

当然,如果令牌过期,它会延迟用户的第一次请求,但它可以确保令牌有效,而不会强制用户再次登录。