跳至主要内容

如何在 Auth.js 和 Next.js 中使用 Prisma ORM

25 分钟

介绍

Auth.js 是一个灵活的开源身份验证库,旨在简化为 Next.js 应用程序添加身份验证的过程。

在本指南中,您将把 Auth.js 集成到一个全新的 Next.js 应用程序中,并将用户持久化到 Prisma Postgres 数据库。您可以在 GitHub 上找到本指南的完整示例。

先决条件

1. 设置项目

创建一个新的 Next.js 应用程序

npx create-next-app@latest authjs-prisma

它将提示你自定义设置。选择默认值

信息
  • 你想使用 TypeScript 吗?
  • 你想使用 ESLint 吗?
  • 你想使用 Tailwind CSS 吗?
  • 你想将代码放在 src/ 目录中吗?
  • 你想使用 App Router 吗? (推荐)
  • 你想为 next dev 使用 Turbopack 吗?
  • 你想自定义导入别名吗(默认为 @/*)?

导航到项目目录

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 数据库时,您需要回答几个问题。选择离您最近的区域,并为您的数据库起一个易记的名称,例如“我的 Auth.js 项目”。

这将创建

  • 一个包含 schema.prisma 文件的 prisma 目录。
  • 一个用于配置 Prisma 的 prisma.config.ts 文件
  • 一个 Prisma Postgres 数据库。
  • 项目根目录中包含 DATABASE_URL.env 文件。
  • 一个指定 Prisma Client 生成位置 (../app/generated/prisma) 的 Schema 配置。

2.2. 定义 Prisma Schema

prisma/schema.prisma 文件中,将 provider 替换为 prisma-client,并为 generator 添加 runtime vercel-edge

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 将 dotenv 添加到 prisma.config.ts

要访问 .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 凭据

在本指南中,您将设置 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 和回调 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: [],
})

接下来,您需要将 Github provider 添加到 auth.ts 文件中

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 中间件文档

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 函数的 action

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.