具有单独后端的NextJS身份验证(如何向受令牌保护的路由发出后续http请求)

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

我已经用谷歌搜索得够多了。互联网上几乎所有与主题相关的指南都会在展示将令牌存储到 cookie 中的示例以及会话刷新示例后结束。但对我来说,最有趣(也是最困难)的部分是在之后 - 当我想向受令牌保护的路由发出 http 请求时。

在我的项目中发出http请求的背景下,主要代理是:

  • 远程后端服务器(支持通过授权标头或 user_token cookie 进行授权)
  • NextJS(服务器端)
  • NextJS(客户端)

所需的身份验证流程:

  1. 用户使用电子邮件和密码填写表单,请求通过服务器操作从 nextjs 客户端发送到 nextjs 服务器;
  2. NextJS 服务器向远程后端发出 http 请求,如果状态正常,则通过
    { cookies } from 'next/headers'
    设置仅 http 的“user_token”cookie,并将响应发送回客户端;
  3. 从现在开始,我希望能够从 NextJS 服务器端和 NextJS 客户端向后端的受保护路由(需要令牌)发出 http 请求。

这是我的问题清单:

a)我注意到,对于使用 NextJS fetch() 函数从 NextJS 服务器端发出的 http 请求,

credentials: "include"
不包含我之前设置的 cookie。所以我想在每次请求之前我都需要使用
cookies().get("user_token")?.value
获取令牌。这是正确的还是有办法让
credentials: "include"
发挥作用?

b)如果(在生产中)NextJS 服务器和后端服务器将在同一域上运行,我的 NextJS 客户端请求会自动包含“user_token”cookie 吗?

c)在开发模式下,我可以做些什么来为 localhost:3000 (nextJS 服务器)和后端域设置“user_token”cookie?或者我应该在每次开发时手动设置它? (目前在开发模式下“user_token”设置为 localhost:3000,因此直接从客户端向后端发出请求时不会发送 cookie)。

备注:

  • 在 NextJS 服务器端,我仅通过 NextJS fetch() 函数向后端发出 http 请求。
  • 在 NextJS 客户端,我仅通过 apisauce 实例向后端发出 http 请求(基本上是 axios)。

我将包含一些代码清单,但是无需查看它们就可以理解我的问题的上下文。

登录服务器操作(简化代码):

export const loginAction = async (state: unknown, formData: unknown): Promise<LoginFormState> => {
  if (!(formData instanceof FormData)) 
    return {
      message: "Invalid payload",
      ok: false
    };

  // Validate form fields
  const validatedFields = LoginFormSchema.safeParse({
    email: formData.get('email'),
    password: formData.get('password'),
  })
 
  // If any form fields are invalid, return early
  if (!validatedFields.success) {
    console.log('validation error');
    return {
      errors: validatedFields.error.flatten().fieldErrors,
    } as LoginFormState
  }

  const loginResponse = await loginPost({
    ...validatedFields.data
  });

  if (!classicNextApiResponseValidator(loginResponse)) {
    const error = await requestErrorFromNextResponse(loginResponse);
    return {
      message: error.description,
      ok: false
    }
  }

  const responseData: T.LoginResponse = await loginResponse.json();
       
  await storeToCookies("user_token", responseData.accessToken);

  if (responseData.emailVerified) {
    await redirectAction("/dashboard", {});
  } else {
    await redirectAction("/emailVerification", {});
  }
 
  return {
    message: "successfully",
    ok: true
  }
};

storeToCookies 函数

"use server";

import { cookies } from 'next/headers';
import { CookiesKey } from './types';

export const storeToCookies = async <T = any>(key: CookiesKey, value: T, options: {} = {}) => {
  if (typeof key === "string")
    cookies().set(
      key,
      typeof value === "string" ? value : JSON.stringify(value),
      {
        httpOnly: true,
        secure: false,
        sameSite: 'lax',
        path: '/',
      }
    );
};

我尝试从nextJS服务器端向受保护的路由(配置文件)发出请求(

credentials: "include"
不起作用,但手动获取cookie并将其作为标头传递是有效的:

export const profileGet = async () => { 
  return fetch(`${CONFIG.BASE_URL}/profile`, { 
    method: "GET",
    credentials: "include",
    headers: DEFAULT_HEADERS,
  });
};

我的用于客户端请求的 apisauce 实例:

const sauce = create({
  withCredentials: true,
  baseURL: CONFIG.BASE_URL,
  headers: {
    Accept: 'application/json',
  }
});
authentication next.js cookies authorization nextjs14
1个回答
0
投票

默认情况下,出于安全原因,cookie 不会在服务器端获取调用中传递。

这就是为什么我们应该将标头传递给 fetch 调用。

import { headers } from "next/headers"

//...
//...
//...
async function getProfile() {
    const response = fetch(`${CONFIG.BASE_URL}/profile`, {
        method: "GET",
        headers: headers(),
    })
    
    if (!response.ok) return null

    return res.json()
}

const PageHome: React.FC<PageHomeProps> = async () => {
    const profile = await getProfile()
    
    //...
    //...
    //...
}

export default PageHome
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.