Next.js 身份验证完整指南

2025-05-24

Next.js 身份验证完整指南

封面图片由Kai Pilger提供

在本指南中,你将学习如何在 Next.js 应用中实现身份验证。我将介绍客户端身份验证、经过身份验证的服务器渲染页面、经过身份验证的 API 路由、受保护的路由以及重定向。

身份验证服务将使用AWS Amplify实现,但这里介绍的想法和策略适用于任何身份验证服务,如Auth0 / Okta或甚至自定义后端实现,只要它提供一种跨客户端和服务器管理会话的方法。

该项目的代码位于此处。视频演示在此处


Next.js 概述

Next.js 将客户端渲染与预渲染 HTML 相结合,形成静态页面和服务器渲染页面。该框架还可以轻松使用 API 路由创建 API。

运行构建时,框架将确定页面是静态生成还是服务器渲染。默认情况下,所有页面都是静态生成的,除非页面使用getServerSideProps函数将 props 传递到页面中。此外,所有 API 路由默认都进行服务器渲染。

Next.js 身份验证概念

在 Next.js 应用中,你通常希望充分利用所有这些功能,并让你的 API 跨框架(客户端和服务器)无缝运行。但问题在于,在客户端和服务器上安全地访问用户会话通常并不容易。

在本指南中,我将向您展示如何启用用户身份验证和授权来实现以下功能:

  1. 客户端身份验证
  2. 在客户端访问用户会话
  3. 受保护的客户端路由
  4. 客户端重定向
  5. 在服务器端路由中访问用户会话(getServerSideProps
  6. 受保护的服务器路由(getServerSideProps
  7. 服务器端重定向(getServerSideProps
  8. 通过 API 路由访问用户会话
  9. 社交登录 (OAuth)
  10. 使用 Next.js 无服务器组件部署应用程序

入门

首先创建一个新的 Next.js 应用:

npx create-next-app next-authentication
Enter fullscreen mode Exit fullscreen mode

接下来,进入新目录并安装依赖项:

cd next-authentication
npm install aws-amplify @aws-amplify/ui-react emotion
Enter fullscreen mode Exit fullscreen mode

接下来,初始化一个新的 Amplify 项目:

amplify init

> Choose defaults when prompted
Enter fullscreen mode Exit fullscreen mode

如果您尚未安装和配置 Amplify CLI,请观看此视频以获取完整的演示。

接下来,添加身份验证服务:

amplify add auth

? Do you want to use the default authentication and security configuration? Default configuration
? How do you want users to be able to sign in? Username
? Do you want to configure advanced settings? No, I am done.
Enter fullscreen mode Exit fullscreen mode

接下来部署身份验证服务:

amplify push --y
Enter fullscreen mode Exit fullscreen mode

启用 Amplify SSR

接下来,要启用 Amplify SSR 支持,请打开pages/_app.js并在文件顶部添加以下内容:

import Amplify from 'aws-amplify'
import config from '../src/aws-exports'
Amplify.configure({
  ...config,
  ssr: true
})
Enter fullscreen mode Exit fullscreen mode

🔥 只需设置ssrtrue即可让您的 Amplify 应用具备 SSR 感知能力。

创建身份验证/配置文件路由

接下来,在pages目录中创建一个名为profile.js的新文件。

在这里,我们将使用withAuthenticator组件启用身份验证。该组件将创建用户身份验证流程,使用户能够使用 MFA 注册并登录。

在此文件中,添加以下代码:

// pages/profile.js
import { useState, useEffect } from 'react'
import { Auth } from 'aws-amplify'
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react'

function Profile() {
  const [user, setUser] = useState(null)
  useEffect(() => {
    // Access the user session on the client
    Auth.currentAuthenticatedUser()
      .then(user => {
        console.log("User: ", user)
        setUser(user)
      })
      .catch(err => setUser(null))
  }, [])
  return (
    <div>
      { user && <h1>Welcome, {user.username}</h1> }
      <AmplifySignOut />
    </div>
  )
}

export default withAuthenticator(Profile)
Enter fullscreen mode Exit fullscreen mode

最后,更新pages/_app.js以添加一些导航来链接页面:

import '../styles/globals.css'
import Link from 'next/link'
import { css } from 'emotion'

import Amplify from 'aws-amplify'
import config from '../src/aws-exports'
Amplify.configure({
  ...config,
  ssr: true
})

export default function MyApp({ Component, pageProps }) {
  return (
    <div>
      <nav className={navStyle}>
        <Link href="/">
          <span className={linkStyle}>Home</span>
        </Link>
        <Link href="/profile">
          <span className={linkStyle}>Profile</span>
        </Link>
      </nav>
      <Component {...pageProps} />
    </div>
  )
}

const linkStyle = css`
  margin-right: 20px;
  cursor: pointer;
`

const navStyle = css`
  display: flex;
`
Enter fullscreen mode Exit fullscreen mode

可选 - 设置组件样式

您可以为身份验证组件配置样式。例如,为了尝试匹配 Next.js 启动器附带的蓝色配色方案,您可以在style/globals.css的底部添加以下内容

:root {
  --amplify-primary-color: #0083e8;
  --amplify-primary-tint: #006ec2;
  --amplify-primary-shade: #006ec2;
}
Enter fullscreen mode Exit fullscreen mode

创建帐户并登录

现在已经创建了个人资料路线,让我们通过创建新帐户并登录来测试它。

npm run dev
Enter fullscreen mode Exit fullscreen mode

单击此处了解更多自定义withAuthenticator组件的方法。

您应该能够导航到/profile路线来创建帐户并登录。

直接使用 Auth 类

如果您想构建自己的自定义身份验证流程,您还可以利用Auth 类,它有超过 30 种用于管理用户身份验证状态的方法,包括signUp、、和等confirmSignUp方法signInforgotPassword

通过 SSR 路由访问用户会话

现在用户可以登录,让我们创建一个新的路线来测试 SSR。

在 pages 目录中创建一个名为/protected.js的新路由。

在这里,我们希望有一条路由在服务器上对用户进行身份验证,并根据用户的身份验证状态返回成功或错误消息。

// pages/protected.js

import { withSSRContext } from 'aws-amplify'

function Protected({ authenticated, username }) {
  if (!authenticated) {
    return <h1>Not authenticated</h1>
  }
  return <h1>Hello {username} from SSR route!</h1>
}

export async function getServerSideProps(context) {
  const { Auth } = withSSRContext(context)
  try {
    const user = await Auth.currentAuthenticatedUser()
    console.log('user: ', user)
    return {
      props: {
        authenticated: true, username: user.username
      }
    }
  } catch (err) {
    return {
      props: {
        authenticated: false
      }
    }
  }
}

export default Protected
Enter fullscreen mode Exit fullscreen mode

然后使用指向新路线的链接更新pages/_app.js中的导航:

<Link href="/protected">
  <span className={linkStyle}>Protected route</span>
</Link>
Enter fullscreen mode Exit fullscreen mode

现在,当您登录后,您将能够在该getServerSideProps方法中访问已验证的用户。您还应该看到用户对象已从终端注销。

这是通过使用withSSRContext函数解构Authaws-amplify调用 来实现的Auth.currentAuthenticatedUser()。当以这种方式访问​​该类Auth时,Amplify 将自动读取请求对象,并允许您在 API 路由和 SSR 路由上访问已登录用户的会话。

通过 API 路由访问用户会话

在此 API 路由中,我们希望访问用户,对于未经身份验证的用户返回 null,对于经过身份验证的用户返回用户名。

为此,在pages/api中创建一个名为check-user.js 的新文件:

// pages/api/check-user.js
import Amplify, { withSSRContext } from 'aws-amplify'
import config from "../../src/aws-exports.js"

// Amplify SSR configuration needs to be enabled within each API route
Amplify.configure({ ...config, ssr: true })

export default async (req, res) => {
  const { Auth } = withSSRContext({ req })
  try {
    const user = await Auth.currentAuthenticatedUser()
    res.json({ user: user.username })
  } catch (err) {
    res.statusCode = 200
    res.json({ user: null })
  }
}
Enter fullscreen mode Exit fullscreen mode

当您导航或尝试访问/api/check-user时,您会注意到,当您通过身份验证时用户对象可用,而当您未通过身份验证时则不可用。

客户端重定向

通常,您需要检测用户是否已登录,并根据用户是否经过身份验证或根据其凭据允许访问或重定向他们。

为此,您可以使用withRouterNext.js 中的钩子,根据用户状态以编程方式进行路由。让我们尝试一下。

在pages目录中创建一个名为protected-client-route.js的新文件。

在这里添加如下代码:

import { useState, useEffect } from 'react'
import { Auth } from 'aws-amplify'
import { useRouter } from 'next/router'

function ProtectedClient() {
  const [user, setUser] = useState(null)
  const router = useRouter()
  useEffect(() => {
    Auth.currentAuthenticatedUser()
      .then(user => setUser(user))
      // if there is no authenticated user, redirect to profile page
      .catch(() => router.push('/profile'))
  }, [])
  if (!user) return null
  return <h1>Hello {user.username} from client route!</h1>
}

export default ProtectedClient
Enter fullscreen mode Exit fullscreen mode

接下来,在pages/_app.js中添加此路由的链接

<Link href="/protected-client-route">
  <span className={linkStyle}>Protected client route</span>
</Link>
Enter fullscreen mode Exit fullscreen mode

如果您尝试访问受保护的客户端路由,如果您未通过身份验证,您将被自动重定向到配置文件路由,如果您通过身份验证,则允许您查看页面。

服务器端重定向

SSR 的优点之一是能够实现服务器端重定向。使用服务器端重定向更安全,因为您可以选择不渲染任何 HTML,而是将用户重定向到另一个页面。

打开pages/protected.js并使用以下代码进行更新:

// pages/protected.js
import { withSSRContext } from 'aws-amplify'

function Protected({ username }) {
  return <h1>Hello {username} from SSR route!</h1>
}

export async function getServerSideProps({ req, res }) {
  const { Auth } = withSSRContext({ req })
  try {
    const user = await Auth.currentAuthenticatedUser()
    return {
      props: {
        authenticated: true,
        username: user.username
      }
    }
  } catch (err) {
    res.writeHead(302, { Location: '/profile' })
    res.end()
  }
  return {props: {}}
}

export default Protected
Enter fullscreen mode Exit fullscreen mode

当您尝试访问此路线时,如果您未登录,您将被重定向到个人资料路线。

社交登录 (OAuth)

要添加社交登录,请运行amplify update auth并选择使用社交提供商应用默认配置

您可以从这里添加 Google、Facebook 或 Amazon 的社交登录。

一旦启用社交登录,您就可以使用以下代码从您的应用程序登录用户:

// username / password + all OAuth providers
Auth.federatedSignIn()

// specifying an OAuth provider
<button onClick={() => Auth.federatedSignIn({provider: 'Facebook'})}>Open Facebook</button>
<button onClick={() => Auth.federatedSignIn({provider: 'Google'})}>Open Google</button>
<button onClick={() => Auth.federatedSignIn({provider: 'Amazon'})}>Open Amazon</button>
Enter fullscreen mode Exit fullscreen mode

使用无服务器框架将 Next.js 应用部署到 AWS

要使用无服务器框架和无服务器下一个组件serverless.yml将应用程序部署到 AWS,首先在应用程序的根目录下创建一个名为的文件。

接下来,添加以下两行配置(您可以将myNextApp更改为您想要使用的任何名称):

myNextApp:
    component: "@sls-next/serverless-component@1.17.0" 
Enter fullscreen mode Exit fullscreen mode

接下来,使用以下方式部署npx

npx serverless
Enter fullscreen mode Exit fullscreen mode

如果您从未使用过 AWS CLI,则可能需要配置您的 AWS 凭证。请参阅此处的基本说明

视频演示

结论

该项目的最终代码位于此处

向 Amplify 团队的Eric Clemmons致以最诚挚的谢意,他领导了这个项目并将此功能融入 Amplify。

对于第 2 部分,我们将学习如何结合 Auth 和 Data 来完成以下任务:

  1. getStaticPaths在 SSG 期间提取数据进行补充
  2. 在 API 路由中进行经过身份验证的 API 调用
  3. getServerSideProps
文章来源:https://dev.to/dabit3/the-complete-guide-to-next-js-authentication-2aco
PREV
使用 Amplify 框架进行用户身份验证的完整指南入门创建我们的应用程序 ID 创建和配置身份验证服务测试后续步骤
NEXT
全栈以太坊和 EVM 开发完整指南