reactjs 刷新firebase id令牌服务器端

aelbi1ox  于 2023-04-05  发布在  React
关注(0)|答案(1)|浏览(104)

我正在使用Next.js 13和firebase auth与id令牌开发一个应用程序。
我想利用Next.JS内置的服务器端组件功能来更快地获取用户数据,因此我需要在初始请求时验证服务器上的id令牌。当没有用户登录受保护的路由时,我想重定向到登录页面。
当用户处于非活动状态超过1小时并且id令牌已过期时,问题就会出现。下一个请求头将发送过期令牌,导致auth.verifyIdToken拒绝它。这将在任何客户端代码有机会运行之前将用户重定向到登录页面,包括user.getIdToken刷新令牌。

服务器端有没有刷新id token的方法?我在这里看到,有一个使用firebase REST API的解决方案,似乎不安全。

背景

我使用firebaseui [package][2]进行登录,它创建了初始的id token和refresh token。然后我有一个AuthContextProvider来提供和刷新客户端的id token:

const ServerAuthContextProvider = ({
  children,
  user,
  cookie,
}: {
  children: ReactNode;
  user: UserRecord;
  cookie: Cookie;
}) => {
  useEffect(() => {
    if (typeof window !== "undefined") {
      (window as any).cookie = cookie;
    }
    return auth.onIdTokenChanged(async (snap) => {
      if (!snap) {
        cookie.remove("__session");
        cookie.set("__session", "", { path: "/" });
        return;
      }
      const token = await snap.getIdToken();
      cookie.remove("__session");
      cookie.set("__session", token, { path: "/" });
    });
  }, [cookie]);

  return (
    <serverAuthContext.Provider
      value={{
        user,
        auth,
      }}
    >
      {children}
    </serverAuthContext.Provider>
  );
};
  );
};

服务器端根组件

const RootLayout = async ({ children }: { children: React.ReactNode }) => {
  const { user } = await verifyAuthToken();
  if (!user) redirect("/login");

  return (
    <html lang="en">
      <body>
        <ServerAuthContextProvider user={user}>
          {children}
        </ServerAuthContextProvider>
      </body>
    </html>
  );
};

服务器端令牌验证

const verifyAuthToken = async () => {
  const auth = getAuth(firebaseAdmin);

  try {
    const session = cookies().get("__session");
    if (session?.value) {
      console.log("found token");
      const token = await auth.verifyIdToken(session.value);
      const { uid } = token;
      console.log("uid found: ", uid);
      const user = await auth.getUser(uid);
      return {
        auth,
        user,
      };
    }
  } catch (error: unknown) {
    if (typeof error === "string") {
      console.log("error", error);
      return {
        auth,
        error,
      };
    } else if (error instanceof Error) {
      console.log("error", error.message);

      return {
        auth,
        error: error.message,
      };
    }
  }
  return {
    auth,
  };
};
jdzmm42g

jdzmm42g1#

对于SSR应用,您应该使用session cookies。与ID令牌不同,它们不会在1小时内过期,您可以将其配置为最多14天处于活动状态。
当用户使用Firebase客户端SDK登录时,您可以使用getIdToken()一次,并向其传递一个API,该API可以生成和设置可以在后续请求中读取的会话cookie。这样您就不必使用侦听器保持令牌更新。
请确保您通过将auth persistence设置为none或显式注销用户来从客户端SDK注销用户,以便在您清除cookie(使用注销API)的情况下,客户端没有用户。

相关问题