How to implement authentication in Next.js
我是Next.js的新手,并且正在尝试使用jwt令牌进行身份验证系统。我想知道什么是最好的/标准的方法来存储jwt令牌和使用身份验证系统进行路由。我一直在尝试来自不同教程/文章的不同方法,但不太了解。这是我尝试过的。
用户登录时,它将用户名/密码发送到单独的API服务器(例如,处理后端内容的新项目),服务器将以
这类似于1.),但是使用
我在Next.js服务器(自定义快递服务器)中编写了身份验证后端。当用户登录时,服务器将对其进行验证,然后设置一个httpOnly cookie。然后的问题是,利用客户端路由(使用Next.js路由器转到URL),它无法检查令牌。例如,如果页面用
我见过很多人,在受保护路由的
由于我们正在隔离,所以我有足够的时间来回答这个问题。这将是一个很长的答案。
Next.js使用App组件初始化页面。 _app页面负责呈现我们的页面。我们在_app.js上对用户进行身份验证,因为我们从getInitialProps返回的任何内容都可以被所有其他页面访问。我们在这里对用户进行身份验证,身份验证决定将传递到页面,从页面到页眉,因此每个页面都可以确定用户是否已通过身份验证。 (请注意,可以使用redux来完成,而无需进行支撑钻孔,但这会使答案更加复杂)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | static async getInitialProps({ Component, router, ctx }) { let pageProps = {}; const user = process.browser ? await auth0.clientAuth() : await auth0.serverAuth(ctx.req); // I explain down below //this will be sent to all the components const auth = { user, isAuthenticated: !!user }; if (Component.getInitialProps) { pageProps = await Component.getInitialProps(ctx); } return { pageProps, auth }; } render() { const { Component, pageProps, auth } = this.props; return <Component {...pageProps} auth={auth} />; } } |
如果我们在浏览器上并且需要检查用户是否已通过身份验证,我们只需从浏览器中检索cookie,这很容易。但是我们总是必须验证令牌。这与浏览器和服务器使用的过程相同。我将在下面解释。但是,如果我们在服务器上。我们无权访问浏览器中的cookie。但是我们可以从" req"对象中读取内容,因为cookie附加到了req.header.cookie。这就是我们访问服务器上Cookie的方式。
1 2 3 4 5 6 7 8 9 | 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; } |
这是getCookieFromReq()。请记住,我们必须考虑功能性。
1 2 3 4 5 6 7 8 | 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()部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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 |
随着Next.JS v8的引入,在NextJS示例页面中放置了一些示例。要遵循的基本思想是:
JWT
- 使用Cookie存储令牌(您可以选择是否进一步加密令牌)
- 发送cookie作为授权标头
OAuth
- 使用第三方身份验证服务,例如OAuth2.0
- 使用护照