使用会话cookie时如何设置auth.currentUser?

问题描述 投票:0回答:1

我正在使用 nextjs 14 应用程序路由器。我的整个后端是 firebase,其中包括应用程序托管、身份验证和 firestore。

在 nextjs 中,据我所知,如果我使用服务器端渲染(SSR),我需要使用会话 cookie 进行身份验证。我正在使用

auth.createSessionCookie()
创建会话 cookie,它是 firebase sdk 的一部分。

使用

auth.creationSessionCookie()
并不能让我登录客户端,即。
auth.currentUser === null
。这是一个问题,因为任何检查身份验证的 Firestore 安全规则都不再起作用,因为
request.auth
也始终是
null

我想要某种类似

signInWithSessionCookie()
的功能,一种将我的会话cookie传递到我的请求中的firestore的方法,或者一些解决方法。但经过研究,就像这个other SO questionfirebase文档一样,我找不到办法做到这一点。但这确实令人惊讶,因为这种身份验证模式本质上是每个 nextjs 应用程序的运行方式,而 firebase 是一个试图支持 nextjs 的庞大服务。我在这里错过了什么吗?

javascript firebase next.js firebase-authentication firebase-app-hosting
1个回答
0
投票

当您使用 Cookie 进行身份验证时,您无法使用 Firebase 客户端 SDK 来管理用户的身份验证状态,而必须完全使用 Cookie 进行管理。 它类似于创建您自己的基于 cookie 的身份验证的传统方法,只不过 Firebase 负责处理令牌/cookie 并根据需要撤销它们。

您必须实现一个 API,一旦用户使用客户端 SDK 登录,该 API 就会获取用户的 Firebase ID 令牌,然后设置会话 cookie。

您最好将 Firebase auth persistence 设置为

NONE
,以便用户稍后从 Firebase 客户端 SDK 中注销。您可以按如下方式实现:

import "server-only";

import { NextResponse } from "next/server";
import { authAdmin } from "@/utils/firebase-admin";
import { cookies } from "next/headers";

// /api/auth/login
export async function POST(request: Request) {
  const authorization = request.headers.get("authorization")?.split(" ")[1];

  const sessionCookie = await authAdmin.createSessionCookie(authorization, {
    expiresIn: 14 * 24 * 60 * 60 * 1000, // 14 days in ms (maximum)
  });

  // setting the session cookie
  cookies().set("session", sessionCookie, {
    httpOnly: true,
    secure: true,
    domain: "localhost",
  });

  return NextResponse.json({ message: "Logged in" });
}
// Sample login page
"use client";

import { auth } from "../../utils/firebase";
import { createUserWithEmailAndPassword, getIdToken } from "firebase/auth";
import { useState } from "react";

export default function Login() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const signUpUser = async (event: any) => {
    event.preventDefault();

    try {
      const userCredential = await createUserWithEmailAndPassword(
        auth,
        email,
        password
      );

      // call POST /api/auth/login with user's token
      const token = await getIdToken(userCredential.user);

      const response = await fetch("/api/auth/login", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
          "Content-Type": "application/json",
        },
      });

      const data = await response.json();
     
      // redirect user
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <form className="max-w-sm mx-auto" onSubmit={signUpUser}>
      <div className="mb-5">
        <label>Your email</label>
        <input
          type="email"
          id="email"
          onChange={(event) => setEmail(event.target.value)}
          value={email}
          required
        />
      </div>
      <div className="mb-5">
        <label>Your password</label>
        <input
          type="password"
          id="password"
          onChange={(event) => setPassword(event.target.value)}
          value={password}
          required
        />
      </div>
      <button type="submit">Sign Up</button>
    </form>
  );
}

用户登录后,您必须使用 cookie 检查他们的身份验证状态。您可以使用 Next Middlewares 来执行此操作,如下所示:

// middleware.ts

import { NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { authAdmin } from "./utils/firebase-admin";

export async function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  if (pathname.startsWith("/_next") || pathname.startsWith("/favicon.ico")) {
    return NextResponse.next();
  }

  const authorization = request.headers.get("authorization")?.split(" ")[1];

  if (!authorization) {
    return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
  }

  try {
    const { uid } = await authAdmin.verifyIdToken(authorization);
    console.log("Current user:", uid)

    return response;
  } catch (e) {
    console.log("failed to decode session cookie")
    // Unauthorized user..
  }
}

我建议创建另一个 API 来获取用户的详细信息,您可以使用它在导航栏等位置呈现当前用户的信息。

总而言之,您必须在服务器端(最好是在中间件中)检查用户的身份验证状态,然后有条件地将用户重定向到登录/仪表板页面。

© www.soinside.com 2019 - 2024. All rights reserved.