如何使用应用程序目录将授权令牌传递给 Next.js 13 中的服务器组件?

day*_*oli 10 authentication cookies http-headers server-side-rendering next.js

我是 Next.js 的新手,正在将 JWT 授权令牌存储在客户端 React 上下文中,并希望将该令牌从客户端上下文“传递”到服务器组件,以便可以从服务器组件检索它通过headers()cookies()函数。

我假设我需要在仅限客户端的代码上“设置”这些标头和 cookie,但是如何设置呢?

我更喜欢使用,headers()因为我可以控制何时/是否发送凭据;对于 cookie,我假设它总是随每个请求一起发送。

Next.js 13 的稳定版本有一个身份验证文档,但我已经从不使用getServerSideProps().

稳定的文档也提到了iron-session,我通过一个如何在 Next.js 13 中读取 cookie 的示例发现了这个问题,但它没有显示如何设置它。

tl;dr如何在客户端设置标头和 cookie,以便可以通过服务器组件中的headers()或函数读取它们?cookies()

Yil*_*maz 3

  • 当用户登录时,您将凭据发送到pages/api/auth/login。您检查验证并创建令牌。

我使用cookies-next库来处理cookies。

import { setCookie } from "cookies-next";

export default async function handler(req: NextApiRequest,res: NextApiResponse)
 {
  // pass all the checking
  const token = await jwt.sign(credentials,secret)
  setCookie("jwt", token, { req, res, maxAge: 60 * 60 * 24 });
}
Run Code Online (Sandbox Code Playgroud)
  • 每次发出请求时,都会将令牌附加到标头中。

使用cookies-next

  import { getCookie } from "cookies-next";

  const jwt = getCookie("jwt");

 const response = await axios.get(`${process.env.BASE/whatever}`, {
    headers: {
      Authorization: `Bearer ${jwt}`,
    },
  });
Run Code Online (Sandbox Code Playgroud)
  • 在服务器端函数之前,我们可以访问req对象并检查用户是否经过身份验证。为了在 next.js 中处理这个问题,我创建了一个端点api/auth/me。我向此端点发送了一个请求,以检查用户是否拥有有效的 jwt。我必须在应用程序目录的顶级组件中执行此操作。我创建了一个身份验证上下文,并在内部useEffect检查用户的状态。我将跟踪状态:

在身份验证上下文中,客户端组件

const fetchUser = async () => {
    setAuthState({
      data: null,
      error: null,
      loading: true,
    });
    try {
      const jwt = getCookie("jwt");

      if (!jwt) {
        return setAuthState({
          data: null,
          error: null,
          loading: false,
        });
      }

      const response = await axios.get(`${process.env.BASE/api/auth/me}`, {
        headers: {
          Authorization: `Bearer ${jwt}`,
        },
      });

      setAuthState({
        data: response.data,
        error: null,
        loading: false,
      });
    } catch (error: any) {
      setAuthState({
        data: null,
        error: error.response.data.errorMessage,
        loading: false,
      });
    }
  };

   useEffect(() => {
     fetchUser();
   }, []);
Run Code Online (Sandbox Code Playgroud)
  • 这是pages/api/auth/me端点。

我在身份验证上下文中发出请求

 export default async function handler(req: NextApiRequest,res: NextApiResponse)
 {
  const bearerToken = req.headers["authorization"] as string;
  const token = bearerToken.split(" ")[1];

  const payload = jwt.decode(token) as { email: string };

  if (!payload.email) {
    return res.status(401).json({
      errorMessage: "Unauthorized request",
    });
  }

  const user = yourFetchUser(payload.email)

  if (!user) {
    return res.status(401).json({
      errorMessage: "User not found",
    });
  }

  return res.json({...user});
}
Run Code Online (Sandbox Code Playgroud)
  • 检查用户是否在导航栏中经过身份验证。

这是一个客户端组件

const { data, loading } = useContext(AuthenticationContext);
Run Code Online (Sandbox Code Playgroud)

根据您设置的数据有条件地显示用户名或登录按钮。