Skip to main content

如何将 Prisma ORM 与 Better-Auth 和 Next.js 结合使用

25 min

介绍

¥Introduction

Better-Auth 是一款面向 Web 应用的现代开源身份验证解决方案。它基于 TypeScript、React 和 Prisma 构建,以提供简单且可扩展的身份验证体验。

¥Better-Auth is a modern, open-source authentication solution for web applications. It's built with TypeScript, React, and Prisma to provide a simple and extensible auth experience.

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

¥In this guide, you'll wire Better-Auth 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 betterauth-nextjs-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/ 目录中吗?Yes

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

  • 你想使用 App Router 吗?Yes

    ¥Would you like to use App Router? Yes

  • 你想使用 Turbopack 吗?Yes

    ¥Would you like to use Turbopack? Yes

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

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

导航到项目目录:

¥Navigate to the project directory:

cd betterauth-nextjs-prisma

这些选择将创建一个现代的 Next.js 项目,其中 TypeScript 确保类型安全,ESLint 确保代码质量,Tailwind CSS 进行样式设置。使用 src/ 目录和 App Router 是新 Next.js 应用的常见约定。

¥These selections will create a modern Next.js project with TypeScript for type safety, ESLint for code quality, and Tailwind CSS for styling. Using the src/ directory and the App Router are common conventions for new Next.js applications.

2. 设置 Prisma

¥ Set up Prisma

接下来,你将 Prisma 添加到你的项目中以管理你的数据库。

¥Next, you'll add Prisma to your project to manage your database.

2.1.安装 Prisma 及其依赖

¥2.1. Install Prisma and dependencies

安装必要的 Prisma 软件包。根据你将 Prisma Postgres 与 Accelerate 还是其他数据库一起使用,依赖略有不同。

¥Install the necessary Prisma packages. The dependencies differ slightly depending on whether you use Prisma Postgres with Accelerate or another database.

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

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

¥Once installed, initialize Prisma in your project:

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

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

¥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 Better-Auth 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 客户端的 output 目录,用作 better-auth/generated/prisma

    ¥An output directory for the generated Prisma Client as better-auth/generated/prisma.

2.2.配置 Prisma 客户端生成器

¥2.2. Configure the Prisma client generator

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

¥Run the following command to create the database tables and generate the Prisma Client:

npx prisma generate

2.3.设置全局 Prisma 客户端

¥2.3. Set up a global Prisma client

在其中创建一个 /lib 目录和一个 prisma.ts 文件。此文件将用于创建和导出你的 Prisma 客户端实例。

¥Create a /lib directory and a prisma.ts file inside it. This file will be used to create and export your Prisma Client instance.

mkdir -p src/lib
touch src/lib/prisma.ts

按如下方式设置 Prisma 客户端:

¥Set up the Prisma client like this:

src/lib/prisma.ts
import { PrismaClient } from "@/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;
警告

我们建议使用连接池(例如 Prisma 加速)来高效管理数据库连接。

¥We recommend using a connection pooler (like Prisma Accelerate) to manage database connections efficiently.

如果你选择不使用 PrismaClient,请避免在长期存在的环境中全局实例化 PrismaClient。请改为按请求创建并释放客户端,以防止耗尽数据库连接。

¥If you choose not to use one, avoid instantiating PrismaClient globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

3. 设置 Better-Auth

¥ Set up Better-Auth

现在是时候集成 Better-Auth 进行身份验证了。

¥Now it's time to integrate Better-Auth for authentication.

3.1.安装并配置 Better-Auth

¥3.1. Install and configure Better-Auth

首先,安装 Better-Auth 核心包:

¥First, install the Better-Auth core package:

npm install better-auth

接下来,生成一个 Better-Auth 将用于签署身份验证令牌的安全密钥。这可确保你的令牌不会被篡改。

¥Next, generate a secure secret that Better-Auth will use to sign authentication tokens. This ensures your tokens cannot be messed with.

npx @better-auth/cli@latest secret

复制生成的密钥,并将其与应用的 URL 一起添加到你的 .env 文件中:

¥Copy the generated secret and add it, along with your application's URL, to your .env file:

.env
# Better-Auth
BETTER_AUTH_SECRET=your-generated-secret
BETTER_AUTH_URL=http://localhost:3000

# Prisma
DATABASE_URL="your-database-url"

现在,在 src/lib/auth.ts 处为 Better-Auth 创建一个配置文件:

¥Now, create a configuration file for Better-Auth at src/lib/auth.ts:

touch src/lib/auth.ts

在此文件中,你将配置 Better-Auth 以使用 Prisma 适配器,这允许它将用户和会话数据持久化到数据库中。你还将启用电子邮件和密码身份验证。

¥In this file, you'll configure Better-Auth to use the Prisma adapter, which allows it to persist user and session data in your database. You will also enable email and password authentication.

src/lib/auth.ts
import { betterAuth } from 'better-auth'
import { prismaAdapter } from 'better-auth/adapters/prisma'
import prisma from '@/lib/prisma'

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: 'postgresql',
}),
})

Better-Auth 还支持其他登录方式,例如社交登录(Google、GitHub 等),你可以在其 documentation 中探索这些方式。

¥Better-Auth also supports other sign-in methods like social logins (Google, GitHub, etc.), which you can explore in their documentation.

src/lib/auth.ts
import { betterAuth } from 'better-auth'
import { prismaAdapter } from 'better-auth/adapters/prisma'
import prisma from '@/lib/prisma'

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: 'postgresql',
}),
emailAndPassword: {
enabled: true,
},
})
信息

如果你的应用在 3000 以外的端口上运行,则必须将其添加到 auth.ts 配置中的 trustedOrigins 中,以避免身份验证请求期间出现 CORS 错误。

¥If your application runs on a port other than 3000, you must add it to the trustedOrigins in your auth.ts configuration to avoid CORS errors during authentication requests.

src/lib/auth.ts
import { betterAuth } from 'better-auth'
import { prismaAdapter } from 'better-auth/adapters/prisma'
import prisma from '@/lib/prisma'

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: 'postgresql',
}),
emailAndPassword: {
enabled: true,
},
trustedOrigins: ['http://localhost:3001'],
})

3.2.将 Better-Auth 模型添加到架构

¥3.2. Add Better-Auth models to your schema

Better-Auth 提供了一个 CLI 命令,可以自动将必要的身份验证模型(UserSessionAccountVerification)添加到你的 schema.prisma 文件中。

¥Better-Auth provides a CLI command to automatically add the necessary authentication models (User, Session, Account, and Verification) to your schema.prisma file.

运行以下命令:

¥Run the following command:

npx @better-auth/cli generate
注意

它会请求确认是否覆盖你现有的 Prisma 模式。选择 y

¥It will ask for confirmation to overwrite your existing Prisma schema. Select y.

这将添加以下模型:

¥This will add the following models:

model User {
id String @id
name String
email String
emailVerified Boolean
image String?
createdAt DateTime
updatedAt DateTime
sessions Session[]
accounts Account[]

@@unique([email])
@@map("user")
}

model Session {
id String @id
expiresAt DateTime
token String
createdAt DateTime
updatedAt DateTime
ipAddress String?
userAgent String?
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@unique([token])
@@map("session")
}

model Account {
id String @id
accountId String
providerId String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
accessToken String?
refreshToken String?
idToken String?
accessTokenExpiresAt DateTime?
refreshTokenExpiresAt DateTime?
scope String?
password String?
createdAt DateTime
updatedAt DateTime

@@map("account")
}

model Verification {
id String @id
identifier String
value String
expiresAt DateTime
createdAt DateTime?
updatedAt DateTime?

@@map("verification")
}

3.3.迁移数据库

¥3.3. Migrate the database

使用架构中的新模型,你需要更新数据库。运行迁移以创建相应的表:

¥With the new models in your schema, you need to update your database. Run a migration to create the corresponding tables:

npx prisma migrate dev --name add-auth-models

4. 设置 API 路由

¥ Set up the API routes

Better-Auth 需要一个 API 端点来处理登录、注册和退出等身份验证请求。你将在 Next.js 中创建一个 catch-all API 路由来处理发送到 /api/auth/[...all] 的所有请求。

¥Better-Auth needs an API endpoint to handle authentication requests like sign-in, sign-up, and sign-out. You'll create a catch-all API route in Next.js to handle all requests sent to /api/auth/[...all].

首先,创建必要的目录和文件:

¥First, create the necessary directory and file:

mkdir -p "src/app/api/auth/[...all]"
touch "src/app/api/auth/[...all]/route.ts"

将以下代码添加到新创建的 route.ts 文件中。此代码使用 Better-Auth 的助手来创建与 Next.js 兼容的 GETPOST 请求处理程序。

¥Add the following code to the newly created route.ts file. This code uses a helper from Better-Auth to create Next.js-compatible GET and POST request handlers.

import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);

接下来,你需要一个客户端实用程序来从你的 React 组件与这些端点进行交互。创建一个新的文件 src/lib/auth-client.ts

¥Next, you'll need a client-side utility to interact with these endpoints from your React components. Create a new file src/lib/auth-client.ts:

touch src/lib/auth-client.ts

添加以下代码,用于创建你将在 UI 中使用的 React 钩子和函数:

¥Add the following code, which creates the React hooks and functions you'll use in your UI:

import { createAuthClient } from 'better-auth/react'

export const { signIn, signUp, signOut, useSession } = createAuthClient()

5. 设置你的页面

¥ Set up your pages

现在,让我们构建用于身份验证的用户界面。创建用于注册、登录和受保护仪表板的页面:

¥Now, let's build the user interface for authentication. Create the pages for signing up, signing in, and a protected dashboard:

mkdir -p src/app/{sign-up,sign-in,dashboard}
touch src/app/{sign-up,sign-in,dashboard}/page.tsx

5.1.注册页面

¥5.1. Sign up page

首先,在 src/app/sign-up/page.tsx 中创建基本的 SignUpPage 组件。这将为你的页面设置主容器和标题。

¥First, create the basic SignUpPage component in src/app/sign-up/page.tsx. This sets up the main container and a title for your page.

src/app/sign-up/page.tsx
"use client";

export default function SignUpPage() {
return (
<main className="max-w-md mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign Up</h1>
</main>
);
}

接下来,从 React 和 Next.js 导入必要的钩子来管理状态和导航。初始化路由和一个状态变量以保存任何潜在的错误消息。

¥Next, import the necessary hooks from React and Next.js to manage state and navigation. Initialize the router and a state variable to hold any potential error messages.

src/app/sign-up/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";

export default function SignUpPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

return (
<main className="max-w-md mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign Up</h1>
</main>
);
}

现在,从 Better-Auth 客户端导入 signUp 函数并添加 handleSubmit 函数。此函数在表单提交时触发,并调用 Better-Auth 提供的 signUp.email 方法,传递用户的名称、电子邮件和密码。

¥Now, import the signUp function from your Better-Auth client and add the handleSubmit function. This function is triggered on form submission and calls the signUp.email method provided by Better-Auth, passing the user's name, email, and password.

src/app/sign-up/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
//add-next-lin
import { signUp } from "@/lib/auth-client";

export default function SignUpPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError(null);

const formData = new FormData(e.currentTarget);

const res = await signUp.email({
name: formData.get("name") as string,
email: formData.get("email") as string,
password: formData.get("password") as string,
});

if (res.error) {
setError(res.error.message || "Something went wrong.");
} else {
router.push("/dashboard");
}
}

return (
<main className="max-w-md mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign Up</h1>
</main>
);
}

要将任何问题告知用户,请添加一个元素,当 error 状态不为空时,该元素有条件地进行渲染。

¥To inform the user of any issues, add an element that conditionally renders when the error state is not null.

src/app/sign-up/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signUp } from "@/lib/auth-client";

export default function SignUpPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError(null);

const formData = new FormData(e.currentTarget);

const res = await signUp.email({
name: formData.get("name") as string,
email: formData.get("email") as string,
password: formData.get("password") as string,
});

if (res.error) {
setError(res.error.message || "Something went wrong.");
} else {
router.push("/dashboard");
}
}

return (
<main className="max-w-md mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign Up</h1>

{error && <p className="text-red-500">{error}</p>}
</main>
);
}

最后,添加 HTML 表单,其中包含用于输入用户名、电子邮件和密码的字段以及提交按钮。

¥Finally, add the HTML form with input fields for the user's name, email, and password, and a submit button.

src/app/sign-up/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signUp } from "@/lib/auth-client";

export default function SignUpPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError(null);

const formData = new FormData(e.currentTarget);

const res = await signUp.email({
name: formData.get("name") as string,
email: formData.get("email") as string,
password: formData.get("password") as string,
});

if (res.error) {
setError(res.error.message || "Something went wrong.");
} else {
router.push("/dashboard");
}
}

return (
<main className="max-w-md mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign Up</h1>

{error && <p className="text-red-500">{error}</p>}

<form onSubmit={handleSubmit} className="space-y-4">
<input
name="name"
placeholder="Full Name"
required
className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2"
/>
<input
name="email"
type="email"
placeholder="Email"
required
className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2"
/>
<input
name="password"
type="password"
placeholder="Password"
required
minLength={8}
className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2"
/>
<button
type="submit"
className="w-full bg-white text-black font-medium rounded-md px-4 py-2 hover:bg-gray-200"
>
Create Account
</button>
</form>
</main>
);
}

5.2.登录页面

¥5.2. Sign in page

对于登录页面,请从 src/app/sign-in/page.tsx 中的基本结构开始。

¥For the sign-in page, start with the basic structure in src/app/sign-in/page.tsx.

src/app/sign-in/page.tsx
"use client";

export default function SignInPage() {
return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign In</h1>
</main>
);
}

现在,添加状态和路由钩子,类似于注册页面。

¥Now, add the state and router hooks, similar to the sign-up page.

src/app/sign-in/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";

export default function SignInPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign In</h1>
</main>
);
}

添加 handleSubmit 函数,这次导入并使用 Better-Auth 中的 signIn.email 方法。

¥Add the handleSubmit function, this time importing and using the signIn.email method from Better-Auth.

src/app/sign-in/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signIn } from "@/lib/auth-client";

export default function SignInPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError(null);

const formData = new FormData(e.currentTarget);

const res = await signIn.email({
email: formData.get("email") as string,
password: formData.get("password") as string,
});

if (res.error) {
setError(res.error.message || "Something went wrong.");
} else {
router.push("/dashboard");
}
}

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign In</h1>
</main>
);
}

添加条件错误消息显示。

¥Add the conditional error message display.

src/app/sign-in/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signIn } from "@/lib/auth-client";

export default function SignInPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError(null);

const formData = new FormData(e.currentTarget);

const res = await signIn.email({
email: formData.get("email") as string,
password: formData.get("password") as string,
});

if (res.error) {
setError(res.error.message || "Something went wrong.");
} else {
router.push("/dashboard");
}
}

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign In</h1>

{error && <p className="text-red-500">{error}</p>}
</main>
);
}

最后,添加用于输入电子邮件和密码的表单字段以及登录按钮。

¥Finally, add the form fields for email and password and a sign-in button.

src/app/sign-in/page.tsx
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signIn } from "@/lib/auth-client";

export default function SignInPage() {
const router = useRouter();
const [error, setError] = useState<string | null>(null);

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError(null);

const formData = new FormData(e.currentTarget);

const res = await signIn.email({
email: formData.get("email") as string,
password: formData.get("password") as string,
});

if (res.error) {
setError(res.error.message || "Something went wrong.");
} else {
router.push("/dashboard");
}
}

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Sign In</h1>

{error && <p className="text-red-500">{error}</p>}

<form onSubmit={handleSubmit} className="space-y-4">
<input
name="email"
type="email"
placeholder="Email"
required
className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2"
/>
<input
name="password"
type="password"
placeholder="Password"
required
className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2"
/>
<button
type="submit"
className="w-full bg-white text-black font-medium rounded-md px-4 py-2 hover:bg-gray-200"
>
Sign In
</button>
</form>
</main>
);
}

5.3.仪表板页面

¥5.3. Dashboard page

这是经过身份验证的用户的受保护页面。从 src/app/dashboard/page.tsx 中的基本组件开始。

¥This is the protected page for authenticated users. Start with the basic component in src/app/dashboard/page.tsx.

src/app/dashboard/page.tsx
"use client";

export default function DashboardPage() {
return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Dashboard</h1>
</main>
);
}

从 Better-Auth 客户端导入 useSession 钩子。此钩子是管理客户端身份验证状态的关键。它提供会话数据和待处理状态。

¥Import the useSession hook from your Better-Auth client. This hook is the key to managing authentication state on the client side. It provides the session data and a pending status.

src/app/dashboard/page.tsx
"use client";

import { useRouter } from "next/navigation";
import { useSession } from "@/lib/auth-client";

export default function DashboardPage() {
const router = useRouter();
const { data: session, isPending } = useSession();

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Dashboard</h1>
</main>
);
}

要保护此路由,请使用 useEffect 钩子。此操作会检查会话是否已加载(!isPending)以及是否存在经过身份验证的用户(!session?.user)。如果两者都是,则会将用户重定向到登录页面。

¥To protect this route, use a useEffect hook. This effect checks if the session has loaded (!isPending) and if there is no authenticated user (!session?.user). If both are true, it redirects the user to the sign-in page.

src/app/dashboard/page.tsx
"use client";

import { useRouter } from "next/navigation";
import { useSession } from "@/lib/auth-client";
import { useEffect } from "react";

export default function DashboardPage() {
const router = useRouter();
const { data: session, isPending } = useSession();

//add-start: redirect if not signed in
useEffect(() => {
if (!isPending && !session?.user) {
router.push("/sign-in");
}
}, [isPending, session, router]);

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Dashboard</h1>
</main>
);
}

为了提供更好的用户体验,请在验证会话时添加加载和重定向状态。

¥To provide a better user experience, add loading and redirecting states while the session is being verified.

src/app/dashboard/page.tsx
"use client";

import { useRouter } from "next/navigation";
import { useSession } from "@/lib/auth-client";
import { useEffect } from "react";

export default function DashboardPage() {
const router = useRouter();
const { data: session, isPending } = useSession();

useEffect(() => {
if (!isPending && !session?.user) {
router.push("/sign-in");
}
}, [isPending, session, router]);

//add-start: loading and redirect states
if (isPending)
return <p className="text-center mt-8 text-white">Loading...</p>;
if (!session?.user)
return <p className="text-center mt-8 text-white">Redirecting...</p>;

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Dashboard</h1>
</main>
);
}

最后,如果用户已通过身份验证,则从 session 对象显示其名称和电子邮件地址。此外,导入 signOut 函数并添加一个调用该函数的按钮,允许用户注销。

¥Finally, if the user is authenticated, display their name and email from the session object. Also, import the signOut function and add a button that calls it, allowing the user to log out.

src/app/dashboard/page.tsx
"use client";

import { useRouter } from "next/navigation";
import { useSession, signOut } from "@/lib/auth-client";
import { useEffect } from "react";

export default function DashboardPage() {
const router = useRouter();
const { data: session, isPending } = useSession();

useEffect(() => {
if (!isPending && !session?.user) {
router.push("/sign-in");
}
}, [isPending, session, router]);

if (isPending)
return <p className="text-center mt-8 text-white">Loading...</p>;
if (!session?.user)
return <p className="text-center mt-8 text-white">Redirecting...</p>;

//add-start: destructure user from session
const { user } = session;

return (
<main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
<h1 className="text-2xl font-bold">Dashboard</h1>
<p>Welcome, {user.name || "User"}!</p>
<p>Email: {user.email}</p>
{/* add-start: sign out button */}
<button
onClick={() => signOut()}
className="w-full bg-white text-black font-medium rounded-md px-4 py-2 hover:bg-gray-200"
>
Sign Out
</button>
</main>
);
}

5.4.主页

¥5.4. Home page

最后,更新主页,以便轻松导航至登录和注册页面。将 src/app/page.tsx 的内容替换为以下内容:

¥Finally, update the home page to provide simple navigation to the sign-in and sign-up pages. Replace the contents of src/app/page.tsx with the following:

src/app/page.tsx
"use client";

import { useRouter } from "next/navigation";

export default function Home() {
const router = useRouter();

return (
<main className="flex items-center justify-center h-screen bg-neutral-950 text-white">
<div className="flex gap-4">
<button
onClick={() => router.push("/sign-up")}
className="bg-white text-black font-medium px-6 py-2 rounded-md hover:bg-gray-200">
Sign Up
</button>
<button
onClick={() => router.push("/sign-in")}
className="border border-white text-white font-medium px-6 py-2 rounded-md hover:bg-neutral-800">
Sign In
</button>
</div>
</main>
);
}

6. 测试一下

¥ Test it out

你的应用现已完全配置。

¥Your application is now fully configured.

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

    ¥Start the development server to test it:

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

    ¥Navigate to http://localhost:3000 in your browser. You should see the home page with "Sign Up" and "Sign In" buttons.

  2. 点击“注册”,创建一个新账户,你将被重定向到仪表板。然后你可以退出并重新登录。

    ¥Click on Sign Up, create a new account, 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

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

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

下一步

¥Next steps

  • 添加对社交登录或魔术链接的支持

    ¥Add support for social login or magic links

  • 实现密码重置和电子邮件验证

    ¥Implement password reset and email verification

  • 添加用户个人资料和账户管理页面

    ¥Add user profile and account management pages

  • 部署到 Vercel 并保护你的环境变量

    ¥Deploy to Vercel and secure your environment variables

  • 使用自定义应用模型扩展你的 Prisma 模式

    ¥Extend your Prisma schema with custom application models

延伸阅读

¥Further reading


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!