Skip to main content

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

25 min

介绍

¥Introduction

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

¥Auth.js is a flexible, open-source authentication library designed to simplify adding authentication to your Next.js applications.

在本指南中,你将把 Auth.js 连接到一个全新的 Next.js 应用中,并将用户持久存储在 Prisma Postgres 数据库中。你可以在 GitHub 上找到本指南的完整示例。

¥In this guide, you'll wire Auth.js into a brand-new Next.js app and persist users in a Prisma Postgres database. You can find a complete example of this guide on GitHub.

先决条件

¥Prerequisites

  • Node.js 18+

  • 熟悉 Next.js 应用路由和 Prisma

    ¥Basic familiarity with Next.js App Router and Prisma

1. 设置你的项目

¥ Set up your project

创建一个新的 Next.js 应用:

¥Create a new Next.js application:

npx create-next-app@latest authjs-prisma

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

¥It will prompt you to customize your setup. Choose the defaults:

信息
  • 你想使用 TypeScript 吗?Yes

    ¥Would you like to use TypeScript? Yes

  • 你想使用 ESLint 吗?Yes

    ¥Would you like to use ESLint? Yes

  • 你想使用 Tailwind CSS 吗?Yes

    ¥Would you like to use Tailwind CSS? Yes

  • 你想将代码放在 src/ 目录中吗?No

    ¥Would you like your code inside a src/ directory? No

  • 你想使用 App Router 吗?(推荐)Yes

    ¥Would you like to use App Router? (recommended) Yes

  • 你想为 next dev 使用 Turbopack 吗?Yes

    ¥Would you like to use Turbopack for next dev? Yes

  • 你想自定义导入别名(默认为 @/*)吗?No

    ¥Would you like to customize the import alias (@/* by default)? No

导航到项目目录:

¥Navigate to the project directory:

cd authjs-prisma

2. 安装和配置 Prisma

¥ Install and configure Prisma

2.1.安装依赖

¥2.1. Install dependencies

要开始使用 Prisma,你需要安装一些依赖:

¥To get started with Prisma, you'll need to install a few dependencies:

npm install prisma tsx --save-dev
npm install @prisma/extension-accelerate @prisma/client

安装完成后,请在你的项目中初始化 Prisma:

¥Once installed, initialize Prisma in your project:

npx prisma init --db --output ../app/generated/prisma
信息

在设置 Prisma Postgres 数据库时,你需要回答几个问题。选择离你最近的区域,并为数据库选择一个容易记住的名称,例如 "我的 Auth.js 项目"

¥You'll need to answer a few questions while setting up your Prisma Postgres database. Select the region closest to your location and a memorable name for your database like "My Auth.js Project"

这将造成:

¥This will create:

  • 一个包含 schema.prisma 文件的 prisma 目录。

    ¥A prisma directory with a schema.prisma file.

  • 一个 Prisma Postgres 数据库。

    ¥A Prisma Postgres database.

  • 一个位于项目根目录、包含 DATABASE_URL 文件的 .env 文件。

    ¥A .env file containing the DATABASE_URL at the project root.

  • 一个模式配置,用于指定 Prisma 客户端的生成位置 (../app/generated/prisma)。

    ¥A schema configuration that specifies where the Prisma Client will be generated (../app/generated/prisma).

2.2.定义 Prisma Schema

¥2.2. Define your Prisma Schema

prisma/schema.prisma 文件中,将提供程序替换为 prisma-client,并将运行时 vercel-edge 添加到生成器:

¥In the prisma/schema.prisma file, swap the provider to prisma-client and add the runtime vercel-edge to the generator:

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

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

将以下模型添加到 schema.prisma 文件,这些模型由 Auth.js 提供:

¥Add the following models to the schema.prisma file, these models are provided by 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")
}

这将创建以下模型:

¥This creates the following models:

  • Account:存储 OAuth 提供商信息(访问令牌、刷新令牌、提供商账户 ID),并允许用户使用多个提供商登录,同时维护单个用户记录。

    ¥Account: Stores OAuth provider information (access tokens, refresh tokens, provider account IDs) and enables users to sign in with multiple providers while maintaining a single user record.

  • Session:使用唯一的会话令牌、用户 ID 和到期时间跟踪经过身份验证的用户会话,以在请求之间维护身份验证状态。

    ¥Session: Tracks authenticated user sessions with a unique session token, user ID, and expiration time to maintain authentication state across requests.

  • User:核心模型存储用户信息(名称、邮箱、个人资料图片)。用户可以拥有来自不同提供商的多个账户和多个活动会话。

    ¥User: The core model storing user information (name, email, profile image). Users can have multiple accounts from different providers and multiple active sessions.

  • VerificationToken:存储用于电子邮件验证、密码重置和其他安全操作的临时令牌,并设置有效期。

    ¥VerificationToken: Stores temporary tokens for email verification, password reset, and other security operations with expiration times.

2.3.配置 Prisma 客户端生成器

¥2.3. Configure the Prisma Client generator

现在,运行以下命令创建数据库表并生成 Prisma 客户端:

¥Now, run the following command to create the database tables and generate the Prisma Client:

npx prisma migrate dev --name init

2.4 创建 Prisma 客户端

¥2.4 Create a Prisma Client

在根目录下创建一个名为 lib 的新文件夹,并在其中创建一个名为 prisma.ts 的新文件。此文件将包含 Prisma 客户端:

¥Create a new folder in the root called lib and create a new file called prisma.ts in it. This file will contain the Prisma Client:

lib/prisma.ts
import { PrismaClient } from '../app/generated/prisma'
import { withAccelerate } from '@prisma/extension-accelerate'

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

const prisma = globalForPrisma.prisma || new PrismaClient().$extends(withAccelerate())

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

export default prisma

3. 设置 Auth.js 凭证

¥ Set up Auth.js credentials

3.1.安装依赖

¥3.1. Install dependencies

安装 Auth.js 依赖:

¥Install the Auth.js dependencies:

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

3.2 凭证

¥3.2 Credentials

在本指南中,你将使用 Github 设置 OAuth。为此,你需要 3 个环境变量:

¥For this guide, you'll be setting up OAuth with Github. For this, you'll need 3 environment variables:

  • AUTH_SECRET - 由 Auth.js 提供

    ¥AUTH_SECRET - Provided by Auth.js

  • CLIENT_ID - 由 Github 提供

    ¥CLIENT_ID - Provided by Github

  • CLIENT_SECRET - 由 Github 提供

    ¥CLIENT_SECRET - Provided by Github

要获取 AUTH_SECRET,你可以运行以下命令:

¥To get the AUTH_SECRET, you can run the following command:

npx auth secret --copy
  • --copy 会将密钥复制到剪贴板。(通常,只需运行 npx auth secret 即可将密钥添加到你的 .env.local 文件中。为了保持整洁,你可以使用 --copy 并将其添加到 Prisma 之前创建的 .env 文件中。)

    ¥--copy will copy the secret to your clipboard. (Normally, just running npx auth secret will add the secret to your .env.local file. To keep it tidy, you can use --copy and add it to the .env file that Prisma created earlier.)

将以下内容添加到 .env 文件:

¥Add the following to the .env file:

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

要获取 CLIENT_IDCLIENT_SECRET,你可以在 Github 上创建一个新的 OAuth 应用。

¥To get the CLIENT_ID and CLIENT_SECRET, you can create a new OAuth application on Github.

  1. 导航到 Github 开发者设置

    ¥Navigate to Github Developer Settings

  2. 点击 New OAuth App

    ¥Click on New OAuth App

  3. 输入你的应用名称、主页 URL 和回调 URL

    ¥Enter a name for your app, a home page URL, and a callback URL

  • 名称:Auth.js + Prisma(或任何你想要的主题)

    ¥Name: Auth.js + Prisma (Or anything you want)

  • 主页 URL:http://localhost:3000

    ¥Homepage URL: http://localhost:3000

  • 回调 URL:http://localhost:3000/api/auth/callback/github

    ¥Callback URL: http://localhost:3000/api/auth/callback/github

  1. 点击“Register application

    ¥Click Register application

  2. 点击 Generate new client secret 并复制 Client IDClient Secret

    ¥Click Generate new client secret and copy the Client ID and Client Secret.

  3. Client IDClient Secret 添加到 .env 文件:

    ¥Add the Client ID and Client Secret to the .env file:

.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

¥3.3. Configure Auth.js

/lib 文件夹中,创建一个名为 auth.ts 的新文件,并添加以下代码:

¥In the /lib folder, create a new file called auth.ts and add the following code:

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

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

接下来,你需要将 Github 提供程序添加到 auth.ts 文件:

¥Next, you'll need to add the Github provider to the auth.ts file:

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 适配器

¥Users will now be able to sign in with Github. To add them to your database, you'll need to use the 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 的新文件。这将保护你的路由,并确保只有经过身份验证的用户才能访问它们:

¥In the root, create a new file called middleware.ts. This will protect your routes and ensure that only authenticated users can access them:

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

3.4.配置路由

¥3.4. Configure the Route

路由处理程序是处理来自 Auth.js 的身份验证请求所必需的。它导出 Auth.js 用于登录、退出和回调操作的 GETPOST 处理程序。

¥The route handler is required to handle authentication requests from Auth.js. It exports the GET and POST handlers that Auth.js uses for sign-in, sign-out, and callback operations.

app/api/auth/[...nextauth]/route.ts 目录下创建一个新文件:

¥Create a new file at app/api/auth/[...nextauth]/route.ts:

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

将以下代码添加到文件:

¥Add the following code to the file:

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

export const { GET, POST } = handlers

就是这样!你的应用现已安全。要查看更多配置选项,请查看 Auth.js 中间件文档

¥That's it! Your app is now secured. To see more configuration options, check out the Auth.js Middleware documentation.

4. 身份验证组件

¥ Auth components

你将创建一个登录和退出按钮。在根目录下创建一个 /components 文件夹,并在其中添加一个名为 auth-components.tsx 的新文件。

¥You will be creating a Sign In and Sign Out button. Create a /components folder in the root and add a new file called auth-components.tsx in it.

首先从 auth 文件导入 signInsignOut 函数:

¥Start by importing the signIn and signOut functions from the auth file:

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

接下来,创建 SignInSignOut 组件:

¥Next, create the SignIn and SignOut components:

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 函数的操作:

¥To add functionality to both of the buttons, add an action to the form that calls the signIn and signOut functions respectively:

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. 将组件添加到你的应用

¥ Add the components to your app

5.1.设置基本页面结构

¥5.1. Set up the basic page structure

/app 文件夹中,将 page.tsx 文件替换为以下代码:

¥In the /app folder, replace the page.tsx file with the following code:

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.添加导入和身份验证检查

¥5.2. Add imports and authentication check

导入所需组件并添加会话检查:

¥Import the required components and add session checking:

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.根据身份验证状态显示内容

¥5.3. Show content based on auth state

添加逻辑,根据用户是否登录显示不同的内容:

¥Add the logic to show different content based on whether the user is signed in:

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.将用户数据添加到页面

¥5.4. Add the user data to the page

如果用户已登录,你可以从数据库中获取用户数据并将其显示在页面上。

¥If the user is signed in, you can fetch the user data from the database and display it on the page.

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. 测试一下

¥ Test it out

警告

在启动开发服务器之前,请注意,如果你使用的是 Next.js v15.2.0 或 v15.2.1,请勿使用 Turbopack,因为存在已知的 issue。通过更新你的 package.json 脚本,从你的开发脚本中移除 Turbopack

¥Before starting the development server, note that if you are using Next.js v15.2.0 or v15.2.1, do not use Turbopack as there is a known issue. Remove Turbopack from your dev script by updating your package.json

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

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

¥This change is not needed on any versions before or after.

你的应用现已完全配置。

¥Your application is now fully configured.

  1. 启动开发服务器进行测试:

    ¥Start the development server to test it:

npm run dev
  1. 在浏览器中导航到 http://localhost:3000。你应该看到带有 "使用 Github 登录" 按钮的主页。

    ¥Navigate to http://localhost:3000 in your browser. You should see the home page with a "Sign In with github" button.

  2. 点击“使用 GitHub 登录”,授权应用,你将被重定向到仪表板。然后你可以退出并重新登录。

    ¥Click on Sign In with github, authorize the app, and you should be redirected to the dashboard. You can then sign out and sign back in.

  3. 要直接在数据库中查看用户数据,你可以使用 Prisma Studio:

    ¥To view the user data directly in your database, you can use Prisma Studio:

npx prisma studio
  1. 这将在你的浏览器中打开一个新标签页,你可以在其中查看 UserSessionAccount 表及其内容。

    ¥This will open a new tab in your browser where you can see the User, Session, and Account tables and their contents.

success

恭喜!现在,你已经拥有一个使用 Auth.js、Prisma 和 Next.js 构建的功能齐全的身份验证系统。

¥Congratulations! You now have a fully functional authentication system built with Auth.js, Prisma, and Next.js.


Stay connected with Prisma

Continue your Prisma journey by connecting with our active community. Stay informed, get involved, and collaborate with other developers:

We genuinely value your involvement and look forward to having you as part of our community!