跳至主要內容

如何使用 Prisma ORM 搭配 Auth.js 與 Next.js

25 分鐘

簡介

Auth.js 是一個靈活的開源驗證函式庫,旨在簡化為您的 Next.js 應用程式新增驗證功能的操作。

在本指南中,您將把 Auth.js 整合到一個全新的 Next.js 應用程式中,並將使用者資料持久化儲存於 Prisma Postgres 資料庫中。您可以在 GitHub 上找到本指南的完整範例。

先決條件

  • Node.js 20+
  • 需基本熟悉 Next.js App Router 與 Prisma

1. 設定您的專案

建立一個新的 Next.js 應用程式

npx create-next-app@latest authjs-prisma

它會提示您自訂設定。請選擇預設值

資訊
  • 您想使用 TypeScript 嗎? Yes
  • 您想使用 ESLint 嗎? Yes
  • 您想使用 Tailwind CSS 嗎? Yes
  • 您想將程式碼放在 src/ 目錄中嗎? No
  • 您想使用 App Router 嗎? (推薦) Yes
  • 您想在 next dev 中使用 Turbopack 嗎? Yes
  • 您想自訂匯入別名 (預設為 @/*) 嗎? No

導覽至專案目錄

cd authjs-prisma

2. 安裝並設定 Prisma

2.1. 安裝依賴項目

要開始使用 Prisma,您需要安裝一些依賴項目

npm install prisma tsx @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg dotenv pg
資訊

如果您使用的是不同的資料庫提供者(MySQL、SQL Server、SQLite),請安裝相應的驅動程式適配器套件,而不是 @prisma/adapter-pg。如需更多資訊,請參閱資料庫驅動程式

安裝完成後,在您的專案中初始化 Prisma

npx prisma init --db --output ../app/generated/prisma
資訊

在設定 Prisma Postgres 資料庫時,您需要回答幾個問題。請選擇最接近您所在地區的位置,並為您的資料庫取一個易記的名稱,例如 "My Auth.js Project"

這將建立:

  • 一個包含 schema.prisma 檔案的 prisma 目錄。
  • 一個用於設定 Prisma 的 prisma.config.ts 檔案
  • 一個 Prisma Postgres 資料庫。
  • 一個在專案根目錄下包含 DATABASE_URL.env 檔案。
  • 一個指定 Prisma Client 生成位置的 schema 設定 (../app/generated/prisma)。

2.2. 定義您的 Prisma Schema

prisma/schema.prisma 檔案中,將 provider 更改為 prisma-client,並將 vercel-edge 執行時期新增至 generator

prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../app/generated/prisma"
runtime = "vercel-edge"
}

datasource db {
provider = "postgresql"
}

將以下模型新增至 schema.prisma 檔案中,這些模型由 Auth.js 提供

prisma/schema.prisma
model Account {
id String @id @default(cuid())
userId String @map("user_id")
type String
provider String
providerAccountId String @map("provider_account_id")
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?

user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@unique([provider, providerAccountId])
@@map("accounts")
}

model Session {
id String @id @default(cuid())
sessionToken String @unique @map("session_token")
userId String @map("user_id")
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@map("sessions")
}

model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime? @map("email_verified")
image String?
accounts Account[]
sessions Session[]

@@map("users")
}

model VerificationToken {
identifier String
token String
expires DateTime

@@unique([identifier, token])
@@map("verification_tokens")
}

這會建立以下模型

  • Account:儲存 OAuth 提供者資訊(存取權杖、更新權杖、提供者帳戶 ID),讓使用者能透過多個提供者登入,同時保持單一使用者紀錄。

  • Session:透過唯一的連線權杖、使用者 ID 與過期時間來追蹤已驗證的使用者連線,以維護跨請求的驗證狀態。

  • User:儲存使用者資訊(姓名、電子郵件、個人頭像)的核心模型。使用者可以擁有多個來自不同提供者的帳戶以及多個有效連線。

  • VerificationToken:為電子郵件驗證、密碼重設及其他安全性操作儲存帶有過期時間的臨時權杖。

2.3 在 prisma.config.ts 加入 dotenv

要存取 .env 檔案中的變數,可以透過執行階段載入,或是使用 dotenv。在 prisma.config.ts 的頂部包含一個 dotenv 的匯入:

import 'dotenv/config'
import { defineConfig, env } from 'prisma/config';
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
});

2.4. 設定 Prisma Client 生成器

現在,執行以下指令來建立資料庫表格並產生 Prisma Client

npx prisma migrate dev --name init
npx prisma generate

2.5 建立 Prisma Client

在根目錄建立一個名為 lib 的新資料夾,並在其中建立一個名為 prisma.ts 的新檔案。此檔案將包含 Prisma Client

lib/prisma.ts
import { PrismaClient } from '../app/generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'

const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!,
})

const globalForPrisma = global as unknown as {
prisma: PrismaClient
}

const prisma = globalForPrisma.prisma || new PrismaClient({
adapter,
})

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

export default prisma

3. 設定 Auth.js 憑證

3.1. 安裝相依套件

安裝 Auth.js 的相依套件

npm install @auth/prisma-adapter next-auth@beta

3.2 憑證 (Credentials)

在本指南中,您將設定 Github 的 OAuth。為此,您需要 3 個環境變數

  • AUTH_SECRET - 由 Auth.js 提供
  • CLIENT_ID - 由 Github 提供
  • CLIENT_SECRET - 由 Github 提供

要取得 AUTH_SECRET,您可以執行以下指令

npx auth secret --copy
  • --copy 會將金鑰複製到您的剪貼簿。(通常,執行 npx auth secret 就會將金鑰新增至 .env.local 檔案。若要保持整潔,您可以使用 --copy 並將其新增至 Prisma 先前建立的 .env 檔案中。)

將以下內容新增至 .env 檔案

.env
DATABASE_URL=<YOUR_DATABASE_URL>
AUTH_SECRET=<YOUR_AUTH_SECRET>

要取得 CLIENT_IDCLIENT_SECRET,您可以在 Github 上建立一個新的 OAuth 應用程式。

  1. 導覽至 Github 開發者設定
  2. 點擊 New OAuth App
  3. 輸入您的應用程式名稱、首頁 URL 與回呼 (Callback) URL
  • 名稱:Auth.js + Prisma(或任何您想要的名稱)
  • 首頁 URL:https://:3000
  • 回呼 URL:https://:3000/api/auth/callback/github
  1. 點擊 Register application
  2. 點擊 Generate new client secret 並複製 Client IDClient Secret
  3. Client IDClient Secret 新增至 .env 檔案
.env
DATABASE_URL=<YOUR_DATABASE_URL>
AUTH_SECRET=<YOUR_AUTH_SECRET>
AUTH_GITHUB_ID=<YOUR_GITHUB_CLIENT_ID>
AUTH_GITHUB_SECRET=<YOUR_GITHUB_CLIENT_SECRET>

3.3. 設定 Auth.js

/lib 資料夾中,建立一個名為 auth.ts 的新檔案,並新增以下程式碼

lib/auth.ts
import NextAuth from 'next-auth'

export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [],
})

接下來,您需要在 auth.ts 檔案中新增 Github 提供者

lib/auth.ts
import NextAuth from 'next-auth'
import GitHub from 'next-auth/providers/github'

export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [GitHub],
})

使用者現在將能夠使用 Github 登入。要將他們新增至您的資料庫,您需要使用 Prisma Adapter

lib/auth.ts
import NextAuth from 'next-auth'
import { PrismaAdapter } from '@auth/prisma-adapter'
import prisma from '@/lib/prisma'
import GitHub from 'next-auth/providers/github'

export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [GitHub],
})

在根目錄中,建立一個名為 middleware.ts 的新檔案。這將保護您的路由,並確保只有經過驗證的使用者才能存取它們

middleware.ts
export { auth as middleware } from '@/lib/auth'

3.4. 設定路由

路由處理器是處理來自 Auth.js 的驗證請求所必需的。它匯出了 Auth.js 用於登入、登出與回呼操作的 GETPOST 處理器。

app/api/auth/[...nextauth]/route.ts 建立一個新檔案

mkdir -p app/api/auth/[...nextauth]
touch app/api/auth/[...nextauth]/route.ts

將以下程式碼新增至該檔案

app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/lib/auth'

export const { GET, POST } = handlers

就是這樣!您的應用程式現在已受到保護。要查看更多設定選項,請查閱 Auth.js Middleware 文件

4. 驗證元件

您將建立登入與登出按鈕。在根目錄建立一個 /components 資料夾,並在其中新增一個名為 auth-components.tsx 的新檔案。

首先從 auth 檔案匯入 signInsignOut 函式

components/auth-components.tsx
import { signIn, signOut } from "@/lib/auth"

接下來,建立 SignInSignOut 元件

components/auth-components.tsx
import { signIn, signOut } from "@/lib/auth"

export function SignIn({ provider }: { provider?: string }) {
return (
<form>
<button className="bg-neutral-700 text-white p-2 rounded-md">
Sign In with {provider}
</button>
</form>
)
}

export function SignOut() {
return (
<form>
<button className="bg-neutral-700 text-white p-2 rounded-md">
Sign Out
</button>
</form>
)
}

要為這兩個按鈕增加功能,請在表單中新增一個動作,分別呼叫 signInsignOut 函式

components/auth-components.tsx
import { signIn, signOut } from "@/lib/auth"

export function SignIn({ provider }: { provider?: string }) {
return (
<form
action={async () => {
"use server"
await signIn(provider)
}}
>
<button className="bg-neutral-700 text-white p-2 rounded-md">
Sign In with {provider}
</button>
</form>
)
}

export function SignOut() {
return (
<form
action={async () => {
"use server"
await signOut()
}}
className="w-full"
>
<button className="bg-neutral-700 text-white p-2 rounded-md">
Sign Out
</button>
</form>
)
}

5. 將元件新增至您的應用程式

5.1. 設定基礎頁面結構

/app 資料夾中,用以下程式碼取代 page.tsx 檔案

app/page.tsx
const Page = async () => {
return (
<div className="min-h-screen bg-black flex items-center justify-center p-4">
<div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
<h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>
</div>
</div>
);
};

export default Page;

5.2. 新增匯入與驗證檢查

匯入所需的元件並新增連線檢查

app/page.tsx
import { SignIn, SignOut } from "@/components/auth-components";
import { auth } from "@/lib/auth";

const Page = async () => {
const session = await auth();

return (
<div className="min-h-screen bg-black flex items-center justify-center p-4">
<div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
<h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>
</div>
</div>
);
};

export default Page;

5.3. 根據驗證狀態顯示內容

新增邏輯以根據使用者是否已登入顯示不同的內容

app/page.tsx
import { SignIn, SignOut } from "@/components/auth-components";
import { auth } from "@/lib/auth";

const Page = async () => {
const session = await auth();

return (
<div className="min-h-screen bg-black flex items-center justify-center p-4">
<div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
<h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>

{!session ? (
<div className="text-center">
<SignIn provider="github" />
</div>
) : (
<div className="space-y-4">
<div className="text-center">
<p className="text-gray-300">Signed in as:</p>
<p className="text-white">{session.user?.email}</p>
</div>

<div className="text-center">
<p className="text-gray-300">Data fetched from DB with Prisma:</p>
</div>

<div className="text-center">
<SignOut />
</div>
</div>
)}
</div>
</div>
);
};

export default Page;

5.4. 將使用者資料新增至頁面

如果使用者已登入,您可以從資料庫獲取使用者資料並將其顯示在頁面上。

app/page.tsx
import { SignIn, SignOut } from "@/components/auth-components";
import { auth } from "@/lib/auth";
import prisma from "@/lib/prisma";

const Page = async () => {
const session = await auth();
let user = null;

if (session) {
user = await prisma.user.findUnique({
where: {
id: session.user?.id,
}
});
}

return (
<div className="min-h-screen bg-black flex items-center justify-center p-4">
<div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
<h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>

{!session ? (
<div className="text-center">
<SignIn provider="github" />
</div>
) : (
<div className="space-y-4">
<div className="text-center">
<p className="text-gray-300">Signed in as:</p>
<p className="text-white">{session.user?.email}</p>
</div>

<div className="text-center">
<p className="text-gray-300">Data fetched from DB with Prisma:</p>
</div>

<div className="bg-neutral-900 rounded p-3">
<pre className="text-xs text-gray-300">
{JSON.stringify(user, null, 2)}
</pre>
</div>

<div className="text-center">
<SignOut />
</div>
</div>
)}
</div>
</div>
);
};

export default Page;

6. 測試應用程式

警告

在啟動開發伺服器之前,請注意如果您使用的是 Next.js v15.2.0 或 v15.2.1,請勿使用 Turbopack,因為存在一個已知的問題。請透過更新您的 package.json 從開發指令中移除 Turbopack

package.json
"script":{
"dev": "next dev --turbopack",
"dev": "next dev",
}

在之前或之後的任何版本中都不需要此變更。

您的應用程式現在已完全設定完成。

  1. 啟動開發伺服器進行測試
npm run dev
  1. 在瀏覽器中導覽至 https://:3000。您應該會看到包含「Sign In with github」按鈕的首頁。

  2. 點擊 Sign In with github,授權應用程式,您應該會被重新導向至儀表板。隨後您可以登出並重新登入。

  3. 要直接在資料庫中檢視使用者資料,您可以使用 Prisma Studio

npx prisma studio
  1. 這會在您的瀏覽器中開啟一個新分頁,您可以在那裡看到 UserSessionAccount 表格及其內容。
成功

恭喜!您現在已經擁有了一個由 Auth.js、Prisma 與 Next.js 建構且功能完整的驗證系統。


與 Prisma 保持聯繫

透過以下方式與我們聯繫,繼續您的 Prisma 旅程: 我們的活躍社群。保持資訊靈通、參與其中,並與其他開發者合作

我們衷心感謝您的參與,並期待您成為我們社群的一份子!

© . This site is unofficial and not affiliated with Prisma Data, Inc.