#使用NextAuth的Next.js電子郵件身份驗證
在Next.js中管理身份驗證可以有很多不同的方法。
在我的網站上,我選擇使用基於電子郵件的身份驗證和JWT令牌,通過NextAuth.js來實現,下面是我是如何做到的。
首先,你需要一個外部數據庫。你可以使用本地數據庫或者雲端數據庫。我選擇了PostgreSQL,但你可以使用任何你想要的數據庫。
假設你已經建立了一個Next.js網站。
執行npm install next-auth pg
安裝NextAuth和PostgreSQL庫。
然後在你的.env
文件中添加以下內容:
1 2 3 4 5
| 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
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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, },
jwt: { secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnX', encryption: true, },
debug: true, })
|
現在根據你的數據存取層進行配置。如果你使用Prisma ORM,可以使用以下命令安裝@next-auth/prisma-adapter
:
1
| npm install @next-auth/prisma-adapter
|
然後在[...nextauth].js
中引入它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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 },
jwt: { secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnX', encryption: true },
debug: true, adapter: PrismaAdapter(prisma) })
|
你需要在schema.prisma
中添加4個模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 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
並添加以下代碼:
1
| import { SessionProvider } from 'next-auth/react'
|
在你的<Component />
調用之前使用它進行包裹:
1 2 3 4 5
| return ( <SessionProvider session={pageProps.session}> <Component {...pageProps} /> </SessionProvider> )
|
現在在你的應用程序中添加一個鏈接,指向/api/auth/signin
。這將是登錄表單。
最後,在需要需要已登錄的會話的頁面中,首先引入useSession
鈎子:
1
| import { useSession } from 'next-auth/react'
|
然後使用它來獲取狀態信息。當會話信息仍在加載時,loading
為true。
1
| const { data: session, status } = useSession()
|
我們可以使用這個session
對象在用戶登錄時在屏幕上顯示信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| {session && ( <p> {session.user.email}{' '} <button className="underline" onClick={() => { signOut() router.push('/') }} > logout </button> </p> )}
|
我們還可以使用這個信息,除非我們已經完成加載,並且會話已建立:
1 2 3 4 5 6 7 8 9
| if (typeof window !== 'undefined' && loading) return null
if (typeof window !== 'undefined' && !session) { router.push('/api/auth/signin') }
if (!session) { return null }
|
如果用戶未登錄,我會將瀏覽器重定向到/api/auth/signin
。你也可以創建一個自定義表單,但這是基本的方法。
在服務器端,你可以使用以下代碼:
1
| import { getSession } from 'next-auth/react'
|
然後在API路由或getServerSideProps({req})
中使用它:
1
| const session = await getSession({ req })
|
這就是我使用NextAuth進行非常基本的身份驗證設置的方法。
NextAuth包提供了非常完整的功能,並提供了許多選項和自定義選擇,詳情請參考https://next-auth.js.org。
tags: [“Next.js”, “NextAuth”, “Email Authentication”, “JWT”, “PostgreSQL”]