【问题标题】:Next.js Authentication with JWTNext.js 使用 JWT 进行身份验证
【发布时间】:2021-05-29 14:47:09
【问题描述】:

我正在将一个项目从 React 转移到 Next.js,并且想知道相同的身份验证过程是否可以。基本上,用户输入他们的用户名和密码,然后通过 API (Node.js/Express) 对照数据库凭据进行检查。所以,我没有使用 Next.js 内部 api 功能,而是与我的 Next.js 项目完全解耦的 API。

如果登录凭据正确,则会将 JWT 令牌发送回客户端。我想将其存储在本地存储中,然后重定向用户。任何未来的 http 请求都将在标头中发送令牌,并通过 API 检查它是否有效。这样做可以吗?我问是因为我看到很多 Next.js 身份验证使用 cookie 或会话,但不知道这是否是我应该采用的“标准”方法。

【问题讨论】:

  • 我有 Next.js/Django JWT 的生产经验,我不得不说如果你使用 JWT,你不能拥有经过身份验证的服务器端渲染页面,你必须只使受保护的路由 CSR而且您无法决定是否应在 Node.js 服务器中重定向您的用户,这将是一种条件渲染,您必须在 useEffect 钩子中决定它,因此它只在客户端而不是服务器上呈现。
  • 您应该将令牌存储在 HttpOnly cookie 中,因为这样它会与所有请求一起传递。使用 localStorage 和 Authorization 标头,问题是当用户访问页面时您无法设置 Authorization 标头(+ 它的安全性有点低,因为在某些情况下恶意 JS 代码可能会访问它)。我经常看到这种 localStorage 模式(过去经常使用它),但这不是最好的方法。此模式适用于来自浏览器的 REST API 调用,但不适用于保护 Web 应用程序页面,cookie 更适合。
  • 感谢您的回复。您提到了用于 REST API 调用的模式,这是我必须做的,因为 api 不在我的 next.js 应用程序中。这是一个外部 API,我必须将标头中的令牌发送到,因为 jwt 令牌是在 node.js 服务器上创建的。话虽如此,您是否建议当 jwt 令牌从服务器发送到客户端时,我将令牌存储在仅 http cookie 中,然后在进行 API 调用时,我从标头中的 cookie 发送令牌,而不是从本地存储中获取令牌?

标签: node.js reactjs express next.js server-side-rendering


【解决方案1】:

我的回答完全基于我的经历和阅读的内容。如果我碰巧错了,请随时纠正。

所以,我的方法是将您的令牌存储在 HttpOnly cookie 中,并始终使用该 cookie 通过 Authorization 标头授权您对 Node API 的请求。我碰巧也在我自己的项目中使用了 Node.js API,所以我知道发生了什么。

以下是我通常如何使用 Next.js 和 Node.js API 处理身份验证的示例。

为了缓解身份验证问题,我在页面中使用 Next.js 内置的 getServerSideProps 函数来构建一个新的可重用高阶组件,该组件将负责身份验证。在这种情况下,我将其命名为isLoggedIn

// isLoggedIn.jsx

export default (GetServerSidePropsFunction) => async (ctx) => {
  // 1. Check if there is a token in cookies. Let's assume that your JWT is stored in 'jwt'.
  const token = ctx.req.cookies?.jwt || null;

  // 2. Perform an authorized HTTP GET request to the private API to check if the user is genuine.
  const { data } = await authenticate(...); // your code here...

  // 3. If there is no user, or the user is not authenticated, then redirect to homepage.
  if (!data) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    };
  }

  // 4. Return your usual 'GetServerSideProps' function.
  return await GetServerSidePropsFunction(ctx);
};

getServerSideProps 将阻止渲染,直到函数被解析,因此请确保您的身份验证速度很快并且不会浪费太多时间。

您可以像这样使用高阶组件。我们称之为profile.jsx,作为个人资料页面。

// profile.jsx

export default isLoggedIn(async (ctx) => {
  // In this component, do anything with the authorized user. Maybe getting his data?
  const token = ctx.req.cookies.jwt;
  const { data } = await getUserData(...); // don't forget to pass his token in 'Authorization' header.

  return {
    props: {
      data,
    },
  },
});

这应该是安全的,因为几乎不可能操纵服务器端的任何东西,除非有人设法找到入侵您的后端的方法。

如果你想发出 POST 请求,那么我通常会这样做。

// profile.jsx

const handleEditProfile = async (e) => {
  const apiResponse = await axios.post(API_URL, data, { withCredentials: true });
  
  // do anything...
};

在 POST 请求中,HttpOnly cookie 也会发送到服务器,因为 withCredentials 参数设置为 true。

还有另一种使用 Next.js 的无服务器 API 将数据发送到服务器的方法。您无需向 API 发出 POST 请求,而是向“代理”Next.js 的无服务器 API 发出 POST 请求,在那里它将向您的 API 执行另一个 POST 请求。

【讨论】:

  • 你有一个包含此工作示例的仓库吗?
  • 您好!抱歉回复晚了,好久没看通知了。我确实有一个存储库,它显示了这个概念的示例用法。查看github.com/lauslim12/Asuna
猜你喜欢
  • 2016-04-07
  • 2023-03-27
  • 2017-07-30
  • 2018-06-30
  • 2018-08-03
  • 2021-02-06
  • 2022-12-03
  • 1970-01-01
  • 2015-06-29
相关资源
最近更新 更多