#使用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。