这个问题可能需要更新的答案,现在 Next.js 12(2021 年 10 月)中有中间件:https://nextjs.org/docs/middleware
我正在起草一个全面的答案来更深入地解释Next.js中的auth,你可以关注progress there on GitHub
这里我将尝试为 Next.js 提出一个总结,使用中间件。
验证后验证令牌并相应重定向
@Yilmaz 从 2020 年 4 月起的大部分答案仍然具有相关性。但是,以前,我们必须使用_app 中的getInitialProps 来处理请求或自定义服务器。
情况不再如此。。使用中间件可以让您以更简洁的代码实现类似的目的。因为中间件是专门为此类用例设计的。
在这里,我假设您使用 RS256 等非对称算法获得 JWT 访问令牌,与之前的答案完全相同。
这是一个可能的实现:
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
const removeCookie = (res: NextResponse, cookieName: string) => {
res.headers.append("Set-Cookie", `${cookieName}=; Max-Age=-1; Path=/`);
return res;
};
export default async function middleware(
req: NextRequest,
ev: NextFetchEvent
) {
const { pathname } = req.nextUrl;
const isPublic = isPublicRoute(pathname);
if (isPublic) {
return NextResponse.next();
}
const accessToken = req.cookies[TOKEN_PATH];
if (!accessToken) {
return NextResponse.redirect(LOGIN_HREF);
}
const isValidToken = await checkAccessToken(accessToken);
if (!isValidToken) {
let res = NextResponse.redirect(LOGIN_HREF);
res = removeCookie(res, TOKEN_PATH);
return res;
}
return NextResponse.next();
}
如何验证令牌
在我的示例中,checkAccessToken 应该验证令牌(不解码,验证签名)。
这是 imo 最复杂的地方。
使用 RSA256 算法时
您还将获得一个 PUBLIC 证书(除了必须...保密的 SECRET 密钥)。尽管您在 middleware 中进行了检查,这是私有且仅限服务器的代码,但这是个好消息,因为理论上您甚至可以在浏览器中使用它。
因此,您可以fetch 身份验证服务器提供的令牌验证端点,也可以自己验证令牌。
不推荐使用获取选项,因为它可能会破坏 Vercel/Next 边缘功能并增加延迟,according to the documentation。
我必须承认,我尚未使用 Next.js 成功验证令牌:) 如果我设法获得一个有效的代码示例,我将更新此答案。
使用对称加密时
您只有一个私人密码。这意味着解码必须在服务器端进行(好消息,您正在编写中间件)。
登录/注销
这不会因中间件而改变。您将访问令牌存储为 httpOnly cookie。注销时,您取消设置此 cookie。
管理这些 Set-Cookies 标头是您的身份验证服务器的责任。
这是一个基本的工作流程,但它应该可以工作。然后,您可以使用类似的方法在混合中添加刷新令牌。
关于令牌撤销
- 如果您在中间件中验证令牌,访问令牌没有立即撤销机制。因为没有调用数据库。
因此,在这种情况下,您需要选择加入短期访问令牌(例如 5 分钟)和刷新令牌。您可以撤销刷新令牌,所以基本上撤销工作但需要几分钟。
- 如果第 3 方服务器验证令牌:则它可以检查列入黑名单的令牌。
注意事项
此外,还有一些建议:大多数在线文章、教程等都侧重于服务器到服务器的通信。或客户端到 API。在访问网页之前检查身份验证时,它们完全烂透了。
例如,无法在浏览器中设置 Authorization 标头。它仅在与 API 通信时有效。网页必须使用 Cookie。
即便如此,如果要从浏览器调用此 API,它最好接受 cookie。
与该领域的专家讨论时,您需要始终阐明 Next.js 用例。
开放式问题:关于基于会话的身份验证
一些框架似乎更喜欢依赖数据库。他们将哈希令牌存储在数据库中,充当会话。如果要检查身份验证,则需要一个服务器来检查用户的令牌与存储的令牌(= 检查是否存在与此令牌的活动会话)。
例如,我想到 Meteor。
但是,我找不到这种机制的名称以及它与 JWT 的实际关系。它们只是 JWT 方法的变体吗?
Next.js official authentication doc 在撰写本文时并未显示中间件,而是使用getServerSideProps。我真的不喜欢这种模式。
它使用一种会话系统,但我不清楚它的内部结构,我什至不确定名称(那是基于会话的身份验证吗?)。
Vercel edge handles examples 展示了如何保护 API 路由,而不是页面(在撰写本文时)