Jwt 如何在Next.js中实现身份验证

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,我正在努力使用jwt令牌的身份验证系统。我想知道用身份验证系统存储jwt令牌和路由的最佳/标准方法是什么。我一直在尝试不同的方法,从不同的教程/文章,但不太理解它。这是我试过的

  • 当用户登录时,它将用户名/密码发送到分离的API服务器(例如,处理后端内容的新项目),服务器将使用
    访问令牌进行响应,然后在Next.js项目中,我使用接收到的令牌设置cookie。在Next.js项目中,受保护的路由将使用
    withAuth
    hoc进行包装,它将检查cookie中的令牌。这种方法的问题在于它容易受到XSS的攻击,因为cookie没有httpOnly标志

  • 这类似于1。)但使用
    localStorage
    ,问题是
    访问令牌
    无法在第一次请求时发送到服务器。(这一点我不确定,但据我所知,在每个HTTP请求中,我必须手动粘贴我的
    访问令牌
    ,那么对于我无法控制的请求呢?例如,第一个请求或使用
    标记)

  • 我在Next.js服务器(自定义express服务器)中编写了身份验证后端。当用户登录时,服务器将对其进行验证,然后设置一个httpOnlycookie。然后问题是,对于客户端路由(使用Next.js路由器转到URL),它无法检查令牌。例如,如果页面使用
    withAuth
    hoc包装,但无法使用javascript访问cookie中的令牌


  • 我见过很多人,在受保护路由的
    getInitialProps
    中,他们只检查cookie/localStorage中是否存在令牌,然后如果令牌被撤销或列入黑名单,他们如何处理它,因为他们没有将令牌发送到服务器?或者我必须在每次客户端页面更改时将令牌发送到服务器吗?

    随着Next.JS v8的引入,下面是一些示例。基本思路如下:

    JWT

    • 使用cookies存储令牌(您可以选择是否进一步加密)
    • 将cookie作为授权标头发送
    OAuth

    • 使用第三方身份验证服务,如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