Next.js身份验证策略

时间:2020-03-22 13:12:40

标签: reactjs authentication session csrf next.js

我一直在尝试为Next.js项目实现可靠的身份验证流程,但现在我完全迷失了。我已经看过Next.js的示例存储库。但是对于完整的解决方案,我还有很多问题。

我有一个express.js API和一个单独的Next.js前端项目。所有数据和身份验证均由API处理。前端仅使用SSR呈现页面。如果我只创建一个整体项目,其中渲染页面和所有数据都由单个服务器处理(我的意思是使用Next.js的自定义服务器选项),那么我将只使用express-session和csurf。这将是管理会话并针对CSRF创建安全性的传统方式。

Express.js API不是必需的。这只是一个例子。它可以是Django API或.Net Core API。要点是,它是一个单独的服务器和一个单独的项目。

我如何拥有一个简单但可靠的结构?我检查了一些我最喜欢的网站(netlify,zeit.co,heroku,spectrum.chat等)。其中一些使用本地存储来存储访问和刷新令牌(易受XSS攻击)。其中一些使用cookie,甚至不使用HTTPOnly(XSS和CSRF都容易受到攻击)。诸如Spectrum.chat之类的示例使用了我上面提到的方式(cookie会话+防止csrf)。

我知道JWT令牌周围有巨大的炒作。但是我发现它们太复杂了。大多数教程只是跳过所有过期,令牌刷新,令牌吊销,黑名单,白名单等。

许多Next.js的会话cookie示例几乎从未提及CSRF。老实说,身份验证始终是我的大问题。有一天,我读到应该使用HTTPOnly cookie,第二天,我看到一个受欢迎的大型站点甚至没有使用它们。或者他们说“永远不要将令牌存储到localStorage”,而繁荣一些大型项目就只是使用这种方法。

有人可以告诉我这种情况的方向吗?

3 个答案:

答案 0 :(得分:6)

免责声明:我是以下免费开源软件包的维护者,但我认为这是适当的,因为这是一个普遍的问题,没有一个很好的答案,因为许多流行的解决方案都具有特定的安全性。问题中出现的缺陷(例如不适当使用CSRF并将Session Token或Web Token暴露给客户端JavaScript)。

NextAuth.js软件包试图使用免费的开源软件解决上述问题。

  • 它与httpOnly一起使用secure cookie。
  • 它具有CSRF保护(双重提交cookie方法,带有签名cookie)。
  • Cookie带有适当的前缀(例如__HOST-__Secure)。
  • 它支持电子邮件/无密码登录和OAuth提供程序(包括很多)。
  • 它同时支持JSON Web令牌(签名+加密)和会话数据库。
  • 您可以在没有数据库的情况下使用它(例如,任何ANSI SQL,MongoDB)。
  • 具有live demoview source)。
  • 这是100%的FOSS,不是商业软件或SaaS解决方案(不出售任何产品)。

示例API路线

例如page/api/auth/[...nextauth.js]

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

const options = {
  providers: [
    // OAuth authentication providers
    Providers.Apple({
      clientId: process.env.APPLE_ID,
      clientSecret: process.env.APPLE_SECRET
    }),
    Providers.Google({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET
    }),
    // Sign in with email (passwordless)
    Providers.Email({
      server: process.env.MAIL_SERVER,
      from: '<no-reply@example.com>'
    }),
  ],
  // MySQL, Postgres or MongoDB database (or leave empty)
  database: process.env.DATABASE_URL
}

export default (req, res) => NextAuth(req, res, options)

示例React组件

例如pages/index.js

import React from 'react'
import { 
  useSession, 
  signin, 
  signout 
} from 'next-auth/client'

export default () => {
  const [ session, loading ] = useSession()

  return <p>
    {!session && <>
      Not signed in <br/>
      <button onClick={signin}>Sign in</button>
    </>}
    {session && <>
      Signed in as {session.user.email} <br/>
      <button onClick={signout}>Sign out</button>
    </>}
  </p>
}

即使您不选择使用它,也可能会找到有用的代码作为参考(例如,JSON Web Tokens的处理方式和how they are rotated in sessions的使用方式。

答案 1 :(得分:3)

对于我当前的项目,我也必须考虑这一点。我使用相同的技术:ExpressJS API和NextJS服务器端渲染的前端。

我选择做的是在ExpressJS API中使用passport.js。 YouTube上的TheNetNin​​ja拥有21集的播放列表,非常好。他向您展示了如何在您的API中实现Google OAuth 2.0,但是这种逻辑会转移到任何其他策略(JWT,电子邮件+密码,Facebook身份验证等)。

在前端,我会从字面上将用户重定向到Express API中的url。该网址将向用户显示Google OAuth屏幕,用户单击“允许”,API会做更多的事情,为特定用户制作Cookie,然后重定向回前端的网址。现在,用户已通过身份验证。

关于HTTPOnly cookie:我选择关闭此功能,因为我将信息存储在前端所需的cookie中。如果启用了此功能,则前端(javascript)无法访问这些cookie,因为它们是HTTPOnly。

以下是我正在谈论的播放列表的链接: https://www.youtube.com/watch?v=sakQbeRjgwg&list=PL4cUxeGkcC9jdm7QX143aMLAqyM-jTZ2x

希望我已为您提供指导。

编辑: 我尚未回答您有关CSURF的问题,但这是因为我不熟悉它。

答案 2 :(得分:0)

我终于找到了解决方法!

现在我正在使用csrf npm软件包,而不是csurf。 csurf只是将csrf转换为快速的中间件。

因此,我在_app的getInitialProps中创建了一个csrfSecret。它创建秘密,并将其设置为httpOnly cookie。稍后,它将创建一个csrfToken并将其与pageProps一起返回。因此,我可以使用window。 NEXT_DATA .props.csrfToken访问它。如果用户刷新页面,则csrfSecret保持不变,但csrfToken被续订。

当我向代理的“ / api / graphql API路由”发出请求时,它首先从x-xsrf-token头获取csrf令牌,并使用csrfSecret cookie值进行验证。 之后,它将提取authToken cookie的值,并将其传递给实际的GraphQL API。

API都是基于令牌的。它只需要一个非过期的访问令牌。 (顺便说一句,它不必是JWT。可以使用任何具有加密强度的随机令牌。这表示参考/不透明令牌。)

实际的API不需要

CSRF检查,因为它不依赖Cookie进行身份验证。它仅检查授权标头。 authToken和csrfSecret都是httpOnly cookie。而且我什至从未将它们存储在客户端内存中。

我认为这是安全的。现在,我对这种解决方案感到满意。