#使用NextAuth的Next.js電子郵件身份驗證

在Next.js中管理身份驗證可以有很多不同的方法。

在我的網站上,我選擇使用基於電子郵件的身份驗證和JWT令牌,通過NextAuth.js來實現,下面是我是如何做到的。

首先,你需要一個外部數據庫。你可以使用本地數據庫或者雲端數據庫。我選擇了PostgreSQL,但你可以使用任何你想要的數據庫。

假設你已經建立了一個Next.js網站。

執行npm install next-auth pg安裝NextAuth和PostgreSQL庫。

然後在你的.env文件中添加以下內容:

DATABASE_URL=<輸入postgresql://數據庫的URL>
EMAIL_SERVER=smtp://user:[[email protected]](/cdn-cgi/l/email-protection):465
EMAIL_FROM=你的名字 <[[email protected]](/cdn-cgi/l/email-protection)>
NEXTAUTH_URL=http://localhost:3000
SECRET=密鑰

確保你添加了一個密鑰。你可以使用https://generate-secret.vercel.app/32生成。

我使用https://mailtrap.io來測試郵件,這在你設置好一切時非常方便。

創建一個具有以下內容的pages/api/auth/[...nextauth].js文件:

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

export default NextAuth({
 providers: [
 Providers.Email({
 server: process.env.EMAIL_SERVER,
 from: process.env.EMAIL_FROM,
 }),
 ],

 database: process.env.DATABASE_URL,
 secret: process.env.SECRET,

 session: {
 jwt: true,
 maxAge: 30 * 24 * 60 * 60, // 30 days
 },

 jwt: {
 secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnX', //在這裡使用一個隨機密鑰令牌
 encryption: true,
 },

 debug: true,
})

現在根據你的數據存取層進行配置。如果你使用Prisma ORM,可以使用以下命令安裝@next-auth/prisma-adapter

npm install @next-auth/prisma-adapter

然後在[...nextauth].js中引入它:

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import { PrismaAdapter } from '@next-auth/prisma-adapter'
import prisma from 'lib/prisma'

export default NextAuth({
 providers: [
 Providers.Email({
 server: process.env.EMAIL_SERVER,
 from: process.env.EMAIL_FROM
 })
 ],

 database: process.env.DATABASE_URL,
 secret: process.env.SECRET,

 session: {
 jwt: true,
 maxAge: 30 * 24 * 60 * 60 // 30 days
 },

 jwt: {
 secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnX', //在這裡使用一個隨機密鑰令牌
 encryption: true
 },

 debug: true,
 adapter: PrismaAdapter(prisma)
})

你需要在schema.prisma中添加4個模型:

model VerificationRequest {
 id String @id @default(cuid())
 identifier String
 token String @unique
 expires DateTime
 createdAt DateTime @default(now())
 updatedAt DateTime @updatedAt

 @@unique([identifier, token])
}

model Account {
 id String @id @default(cuid())
 providerType String
 providerId String
 providerAccountId String
 refreshToken String?
 accessToken String?
 accessTokenExpires DateTime?
 createdAt DateTime @default(now())
 updatedAt DateTime @updatedAt
 user User @relation(fields: [userId], references: [id])
 userId Int
 @@unique([providerId, providerAccountId])
}

model Session {
 id String @id @default(cuid())
 expires DateTime
 sessionToken String @unique
 accessToken String @unique
 createdAt DateTime @default(now())
 updatedAt DateTime @updatedAt
 user User @relation(fields: [userId], references: [id])
 userId Int
}

model User {
 id String @id @default(cuid())
 name String?
 email String? @unique
 emailVerified DateTime?
 image String?
 createdAt DateTime @default(now())
 updatedAt DateTime @updatedAt
 accounts Account[]
 sessions Session[]
}

記得在修改模型後運行npx prisma migrate dev以應用更改到數據庫。

現在打開pages/_app.js並添加以下代碼:

import { SessionProvider } from 'next-auth/react'

在你的<Component />調用之前使用它進行包裹:

return (
<SessionProvider session={pageProps.session}>
 <Component {...pageProps} />
</SessionProvider>
)

現在在你的應用程序中添加一個鏈接,指向/api/auth/signin。這將是登錄表單。

最後,在需要需要已登錄的會話的頁面中,首先引入useSession鈎子:

import { useSession } from 'next-auth/react'

然後使用它來獲取狀態信息。當會話信息仍在加載時,loading為true。

const { data: session, status } = useSession()

我們可以使用這個session對象在用戶登錄時在屏幕上顯示信息:

{session && (
 <p>
 {session.user.email}{' '}
 <button
 className="underline"
 onClick={() => {
 signOut()
 router.push('/')
 }}
 >
 logout
 </button>
 </p>
)}

我們還可以使用這個信息,除非我們已經完成加載,並且會話已建立:

if (typeof window !== 'undefined' && loading) return null

if (typeof window !== 'undefined' && !session) {
 router.push('/api/auth/signin')
}

if (!session) { //用於服務器端渲染
 return null
}

如果用戶未登錄,我會將瀏覽器重定向到/api/auth/signin。你也可以創建一個自定義表單,但這是基本的方法。

在服務器端,你可以使用以下代碼:

import { getSession } from 'next-auth/react'

然後在API路由或getServerSideProps({req})中使用它:

const session = await getSession({ req })

這就是我使用NextAuth進行非常基本的身份驗證設置的方法。

NextAuth包提供了非常完整的功能,並提供了許多選項和自定義選擇,詳情請參考https://next-auth.js.org