Jwt 如何在Next.js中实现身份验证
我不熟悉Next.js,我正在努力使用jwt令牌的身份验证系统。我想知道用身份验证系统存储jwt令牌和路由的最佳/标准方法是什么。我一直在尝试不同的方法,从不同的教程/文章,但不太理解它。这是我试过的Jwt 如何在Next.js中实现身份验证,jwt,next.js,server-side-rendering,Jwt,Next.js,Server Side Rendering,我不熟悉Next.js,我正在努力使用jwt令牌的身份验证系统。我想知道用身份验证系统存储jwt令牌和路由的最佳/标准方法是什么。我一直在尝试不同的方法,从不同的教程/文章,但不太理解它。这是我试过的 当用户登录时,它将用户名/密码发送到分离的API服务器(例如,处理后端内容的新项目),服务器将使用访问令牌进行响应,然后在Next.js项目中,我使用接收到的令牌设置cookie。在Next.js项目中,受保护的路由将使用withAuthhoc进行包装,它将检查cookie中的令牌。这种方法的问题
访问令牌进行响应,然后在Next.js项目中,我使用接收到的令牌设置cookie。在Next.js项目中,受保护的路由将使用withAuth
hoc进行包装,它将检查cookie中的令牌。这种方法的问题在于它容易受到XSS的攻击,因为cookie没有httpOnly标志
localStorage
,问题是访问令牌
无法在第一次请求时发送到服务器。(这一点我不确定,但据我所知,在每个HTTP请求中,我必须手动粘贴我的访问令牌
,那么对于我无法控制的请求呢?例如,第一个请求或使用
标记)
withAuth
hoc包装,但无法使用javascript访问cookie中的令牌
我见过很多人,在受保护路由的
getInitialProps
中,他们只检查cookie/localStorage中是否存在令牌,然后如果令牌被撤销或列入黑名单,他们如何处理它,因为他们没有将令牌发送到服务器?或者我必须在每次客户端页面更改时将令牌发送到服务器吗?随着Next.JS v8的引入,下面是一些示例。基本思路如下:
JWT
- 使用cookies存储令牌(您可以选择是否进一步加密)
- 将cookie作为授权标头发送
- 使用第三方身份验证服务,如OAuth2.0
- 使用护照
- 既然我们在隔离区,我有足够的时间回答这个问题。这将是一个很长的答案
Next.js使用应用程序组件初始化页面_应用程序页面负责呈现我们的页面。我们在_app.js上对用户进行身份验证,因为我们从getInitialProps返回的任何内容都可以被所有其他页面访问。我们在这里对用户进行身份验证,身份验证决定将被传递到各个页面,从页面到页眉,因此每个页面都可以决定用户是否经过身份验证。(注意,可以使用redux进行,而无需钻柱,但这会使答案更加复杂)
下面是getCookieFromReq()。记住,我们必须考虑功能
const getCookieFromReq = (req, cookieKey) => {
const cookie = req.headers.cookie
.split(";")
.find((c) => c.trim().startsWith(`${cookieKey}=`));
if (!cookie) return undefined;
return cookie.split("=")[1];
};
一旦我们得到cookie,我们就必须对它进行解码,提取过期时间,看看它是否有效。这部分很简单。我们必须检查的另一件事是jwt的签名是否有效。对称或非对称算法用于对jwt进行签名。必须使用私钥来验证对称算法的签名。RS256是API的默认非对称算法。使用RS256的服务器提供一个链接,让jwt使用密钥验证签名。您可以使用[jwks rsa][1],也可以自己使用。您必须创建一个证书,然后验证令牌是否有效
假设我们的用户现在已通过身份验证。你说,“我见过很多人,在受保护路由的getInitialProps中,他们只检查cookie/localStorage中的存在令牌。”。我们使用受保护的路由只允许授权用户访问。为了访问这些路由,用户必须显示其jwt令牌,express.js使用中间件检查用户的令牌是否有效。既然您已经看到了很多示例,我将跳过这一部分
“那么,如果令牌被吊销或列入黑名单,他们如何处理它,因为他们没有将令牌发送到服务器?或者我必须在每次客户端页面更改时将令牌发送到服务器?”
通过验证令牌过程,我们可以100%确定令牌是否有效。当客户机要求服务器访问某些机密数据时,客户机必须向服务器发送令牌。想象一下,当您装载组件时,组件要求服务器从受保护的路由获取一些数据。服务器将提取req对象,获取jwt并使用它从受保护的路由获取数据。浏览器和服务器获取数据的实现是不同的。如果浏览器发出请求,它只需要相对路径,而服务器需要绝对路径。您应该知道,获取数据是在组件的getInitialProps()上完成的,此函数在客户端和服务器上都执行。下面是您应该如何实现它。我刚刚附加了getInitialProps()部分
包括JWT、OAuth等在内的大量示例,在线程末尾。请参阅作为注释发布,因为我是此项目的维护人员,因此可能不适合回答(特别是因为它不是一个解释),但您可能希望签出,因为它支持JWT和/或OAuth提供商的基于数据库的身份验证,并且可以非常轻松地发送电子邮件,以安全的方式,解决所描述的一些问题。检疫万岁,谢谢!救生员!我不知道我可以在
getInitialProps()
中访问\u app.js
中的组件。对于我的用例,我需要将身份验证传递给组件,以防组件对另一台服务器的API请求需要令牌访问:page
async serverAuth(req) {
// console.log(req.headers.cookie) to check
if (req.headers.cookie) {
const token = getCookieFromReq(req, "jwt");
const verifiedToken = await this.verifyToken(token);
return verifiedToken;
}
return undefined;
}
const getCookieFromReq = (req, cookieKey) => {
const cookie = req.headers.cookie
.split(";")
.find((c) => c.trim().startsWith(`${cookieKey}=`));
if (!cookie) return undefined;
return cookie.split("=")[1];
};
MyComponent.getInitialProps = async (ctx) => {
const another = await getSecretData(ctx.req);
//reuslt of fetching data is passed to component as props
return { superValue: another };
};
const getCookieFromReq = (req, cookieKey) => {
const cookie = req.headers.cookie
.split(";")
.find((c) => c.trim().startsWith(`${cookieKey}=`));
if (!cookie) return undefined;
return cookie.split("=")[1];
};
const setAuthHeader = (req) => {
const token = req ? getCookieFromReq(req, "jwt") : Cookies.getJSON("jwt");
if (token) {
return {
headers: { authorization: `Bearer ${token}` },
};
}
return undefined;
};
export const getSecretData = async (req) => {
const url = req ? "http://localhost:3000/api/v1/secret" : "/api/v1/secret";
return await axios.get(url, setAuthHeader(req)).then((res) => res.data);
};
[1]: https://www.npmjs.com/package/jwks-rsa