如何在Next.js

时间:2018-04-19 11:41:54

标签: jwt serverside-rendering next.js ssr

我是Next.js的新手,我正在使用jwt令牌与身份验证系统进行斗争。我想知道使用身份验证系统存储jwt令牌和路由的最佳/标准方法是什么。我一直在尝试不同的方法,从不同的教程/文章,但不太明白。这是我尝试过的。

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

  2. 这类似于1.)但是使用localStorage,问题是access-token无法在第一次请求时发送到服务器。 (这个我不确定,但根据我的理解,在每个http请求中,我必须手动粘贴access-token,那么我无法控制的请求呢?例如,首先请求或使用{{1} }标签)。

  3. 我在Next.js服务器(自定义快速服务器)中编写了身份验证后端。用户登录时,服务器将验证它,然后设置 httpOnly cookie。然后问题是,使用客户端路由(使用Next.js路由器转到url),它无法检查令牌。例如,如果页面用<a> hoc包装,但它无法使用javascript访问cookie中的令牌。

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

2 个答案:

答案 0 :(得分:11)

由于我们正在隔离,所以我有足够的时间来回答这个问题。这将是一个很长的答案。

Next.js使用App组件初始化页面。 _app页面负责呈现我们的页面。我们在_app.js上对用户进行身份验证,因为我们从getInitialProps返回的任何内容都可以被所有其他页面访问。我们在这里对用户进行身份验证,身份验证决定将传递到页面,从页面到页眉,因此每个页面都可以确定用户是否已通过身份验证。 (请注意,可以使用redux来完成,而无需进行支撑钻孔,但这会使答案更加复杂)

  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的方式。

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()。记住我们必须考虑功能性。

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()部分。

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

答案 1 :(得分:1)

随着Next.JS v8的引入,在NextJS example page中也放置了一些示例。要遵循的基本思想是:

JWT

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

OAuth

  • 使用第三方身份验证服务,例如OAuth2.0
  • 使用护照