如何将 Prisma ORM 和 Prisma Postgres 与 Better Auth 和 Next.js 结合使用
介绍
¥Introduction
Better Auth 是一款面向 Web 应用的现代开源身份验证解决方案。它是一个使用 TypeScript 构建的生成器,提供简单且可扩展的身份验证体验,并支持多种数据库适配器,包括 Prisma。
¥Better Auth is a modern, open-source authentication solution for web applications. It's built with TypeScript and provides a simple and extensible auth experience with support for multiple database adapters, including Prisma.
在本指南中,你将把 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
-
熟悉 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 tsx @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg dotenv pg
如果你使用其他数据库提供商(MySQL、SQL Server、SQLite),请安装相应的驱动程序适配器包,而不是 @prisma/adapter-pg。欲了解更多信息,请参阅 数据库驱动程序。
¥If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of @prisma/adapter-pg. For more information, see Database drivers.
安装完成后,请在你的项目中初始化 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
prismadirectory with aschema.prismafile -
Prisma Postgres 数据库
¥A Prisma Postgres database
-
项目根目录下的
.env文件,其中包含DATABASE_URL文件¥A
.envfile containing theDATABASE_URLat the project root -
用于存放生成的 Prisma Client 的
output目录(作为better-auth/generated/prisma文件)¥An
outputdirectory for the generated Prisma Client asbetter-auth/generated/prisma
2.2.配置 Prisma
¥2.2. Configure Prisma
在项目根目录中创建 prisma.config.ts 文件,并添加以下内容:
¥Create a prisma.config.ts file in the root of your project with the following content:
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'),
},
});
由于 dotenv 包是 Next.js 的依赖,因此应该已经安装。否则,请使用以下命令安装:
¥The dotenv package should already be installed as it's a Next.js dependency. If not, install it using:
npm install dotenv
2.3.生成 Prisma 客户端
¥2.3. Generate the Prisma client
运行以下命令创建数据库表并生成 Prisma 客户端:
¥Run the following command to create the database tables and generate the Prisma Client:
npx prisma generate
2.4.设置全局 Prisma 客户端
¥2.4. Set up a global Prisma client
在 src 目录中,创建 lib 文件夹并在其中创建一个 prisma.ts 文件。此文件将用于创建和导出你的 Prisma 客户端实例。
¥In the src directory, create a lib folder 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:
import { PrismaClient } from "@/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;
我们建议使用连接池(例如 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:
# Better Auth
BETTER_AUTH_SECRET=your-generated-secret
BETTER_AUTH_URL=http://localhost:3000
# Prisma
DATABASE_URL="your-database-url"
现在,为 Better Auth 创建一个配置文件。在 src/lib 目录中,创建一个 auth.ts 文件:
¥Now, create a configuration file for Better Auth. In the src/lib directory, create an auth.ts file:
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.
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.
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.
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 命令,可以自动将必要的身份验证模型(User、Session、Account 和 Verification)添加到你的 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
npx prisma generate
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].
在 src/app/api 目录中,创建一个 auth/[...all] 文件夹结构,并在其中创建一个 route.ts 文件:
¥In the src/app/api directory, create an auth/[...all] folder structure and a route.ts file inside it:
mkdir -p "src/app/api/auth/[...all]"
touch "src/app/api/auth/[...all]/route.ts"
将以下代码添加到新创建的 route.ts 文件中。此代码使用 Better Auth 的辅助函数来创建与 Next.js 兼容的 GET 和 POST 请求处理程序。
¥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. In the src/lib directory, create an auth-client.ts file:
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
现在,让我们构建用于身份验证的用户界面。在 src/app 目录中,创建以下文件夹结构:
¥Now, let's build the user interface for authentication. In the src/app directory, create the following folder structure:
-
sign-up/page.tsx -
sign-in/page.tsx -
dashboard/page.tsx
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.
"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.
"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.
"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.
"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.
"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.
"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.
"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.
"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.
"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.
"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.
"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.
"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.
"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]);
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.
"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]);
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.
"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>;
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>
<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:
"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.
-
启动开发服务器进行测试:
¥Start the development server to test it:
npm run dev
-
在浏览器中导航到
http://localhost:3000。你应该看到带有 "注册" 和 "登录" 按钮的主页。¥Navigate to
http://localhost:3000in your browser. You should see the home page with "Sign Up" and "Sign In" buttons. -
点击“注册”,创建一个新账户,你将被重定向到仪表板。然后你可以退出并重新登录。
¥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.
-
要直接在数据库中查看用户数据,你可以使用 Prisma Studio。
¥To view the user data directly in your database, you can use Prisma Studio.
npx prisma studio
-
这将在你的浏览器中打开一个新标签页,你可以在其中查看
User、Session和Account表及其内容。¥This will open a new tab in your browser where you can see the
User,Session, andAccounttables and their contents.
恭喜!你现在拥有一个使用 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:
- Follow us on X for announcements, live events and useful tips.
- Join our Discord to ask questions, talk to the community, and get active support through conversations.
- Subscribe on YouTube for tutorials, demos, and streams.
- Engage on GitHub by starring the repository, reporting issues, or contributing to an issue.