如何在 Auth.js 和 Next.js 中使用 Prisma ORM
介绍
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 吗?
是 - 你想使用 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
generator client {
provider = "prisma-client"
output = "../app/generated/prisma"
runtime = "vercel-edge"
}
datasource db {
provider = "postgresql"
}
将以下模型添加到 schema.prisma 文件中,这些模型由 Auth.js 提供。
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。
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 文件中
DATABASE_URL=<YOUR_DATABASE_URL>
AUTH_SECRET=<YOUR_AUTH_SECRET>
要获取 CLIENT_ID 和 CLIENT_SECRET,您可以在 Github 上创建一个新的 OAuth 应用程序。
- 导航到 Github 开发者设置
- 点击
New OAuth App - 输入您的应用程序名称、主页 URL 和回调 URL
- 名称:
Auth.js + Prisma(或任何您想要的名称) - 主页 URL:
https://:3000 - 回调 URL:
https://:3000/api/auth/callback/github
- 点击
Register application - 点击
Generate new client secret并复制Client ID和Client Secret。 - 将
Client ID和Client Secret添加到.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 的新文件并添加以下代码
import NextAuth from 'next-auth'
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [],
})
接下来,您需要将 Github provider 添加到 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
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 的新文件。这将保护您的路由并确保只有经过身份验证的用户才能访问它们。
export { auth as middleware } from '@/lib/auth'
3.4. 配置路由
路由处理程序需要处理来自 Auth.js 的身份验证请求。它导出了 Auth.js 用于登录、登出和回调操作的 GET 和 POST 处理程序。
在 app/api/auth/[...nextauth]/route.ts 创建一个新文件
mkdir -p app/api/auth/[...nextauth]
touch app/api/auth/[...nextauth]/route.ts
将以下代码添加到文件中
import { handlers } from '@/lib/auth'
export const { GET, POST } = handlers
大功告成!您的应用程序现在已经安全了。要查看更多配置选项,请查看 Auth.js 中间件文档。
4. 身份验证组件
您将创建一个登录和登出按钮。在根目录中创建一个 /components 文件夹,并在其中添加一个名为 auth-components.tsx 的新文件。
首先从 auth 文件中导入 signIn 和 signOut 函数
import { signIn, signOut } from "@/lib/auth"
接下来,创建 SignIn 和 SignOut 组件
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>
)
}
为了给这两个按钮添加功能,在表单中添加一个分别调用 signIn 和 signOut 函数的 action
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 文件替换为以下代码
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. 添加导入和身份验证检查
导入所需组件并添加会话检查
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. 根据认证状态显示内容
添加逻辑以根据用户是否登录显示不同的内容
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. 将用户数据添加到页面
如果用户已登录,您可以从数据库中获取用户数据并将其显示在页面上。
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。
"script":{
"dev": "next dev --turbopack",
"dev": "next dev",
}
在之前或之后的任何版本上,都不需要此更改。
你的应用程序现在已完全配置。
- 启动开发服务器以进行测试
npm run dev
-
在浏览器中导航到
https://:3000。您应该会看到主页,其中有一个“Sign In with github”按钮。 -
点击 Sign In with github,授权应用程序,您应该会被重定向到仪表板。然后您可以登出并重新登录。
-
要直接在数据库中查看用户数据,您可以使用 Prisma Studio
npx prisma studio
- 这将在浏览器中打开一个新标签页,你可以在其中查看
User、Session和Account表及其内容。
恭喜!您现在已经拥有一个使用 Auth.js、Prisma 和 Next.js 构建的完全正常运行的身份验证系统。
与 Prisma 保持联系
通过以下方式与我们保持联系,继续你的 Prisma 之旅: 我们的活跃社区。保持信息灵通,参与其中,并与其他开发人员协作。
- 在 X 上关注我们 获取公告、直播活动和实用技巧。
- 加入我们的 Discord 提问、与社区交流,并通过对话获得积极支持。
- 在 YouTube 上订阅 获取教程、演示和直播。
- 在 GitHub 上参与 加星收藏存储库、报告问题或为问题做出贡献。