Skip to main content

如何将 Prisma ORM 和 Prisma Postgres 与 Clerk Auth 和 Astro 结合使用

25 min

介绍

¥Introduction

Clerk 是一个嵌入式身份验证提供程序,可处理注册、登录、用户管理和 Webhook,让你无需再亲自动手。

¥Clerk is a drop-in auth provider that handles sign-up, sign-in, user management, and webhooks so you don't have to.

在本指南中,你将把 Clerk 集成到全新的 Astro 应用中,并将用户持久化到 Prisma Postgres 数据库中。你可以在 GitHub 上找到本指南的完整示例。

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

先决条件

¥Prerequisites

1. 设置你的项目

¥ Set up your project

创建一个新的 Astro 项目:

¥Create a new Astro project:

npm create astro@latest

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

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

信息
  • 你希望如何启动你的新项目?Empty

    ¥How would you like to start your new project? Empty

  • 安装依赖?Yes

    ¥Install dependencies? Yes

  • 是否初始化新​​的 git 存储库?Yes

    ¥Initialize a new git repository? Yes

进入新创建的项目目录:

¥Navigate into the newly created project directory:

cd <your-project-name>

2. 设置 Clerk

¥ Set up Clerk

2.1.创建一个新的 Clerk 应用

¥2.1. Create a new Clerk application

登录 到 Clerk 并导航到主页。从那里,按下 Create Application 按钮创建一个新的应用。输入标题,选择登录选项,然后点击 Create Application

¥Sign in to Clerk and navigate to the home page. From there, press the Create Application button to create a new application. Enter a title, select your sign-in options, and click Create Application.

信息

本指南将使用 Google、Github 和电子邮件登录选项。

¥For this guide, the Google, Github, and Email sign in options will be used.

安装 Clerk Astro SDK 和 Node 适配器:

¥Install the Clerk Astro SDK and Node adapter:

npm install @clerk/astro @astrojs/node

在 Clerk 控制面板中,导航至 API 密钥页面。在“快速复制”部分,复制你的 Clerk 可发布密钥和私钥。将你的键粘贴到项目根目录下的 .env 文件中:

¥In the Clerk Dashboard, navigate to the API keys page. In the Quick Copy section, copy your Clerk Publishable and Secret Keys. Paste your keys into .env in the root of your project:

.env
PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>

2.2.配置 Astro 与 Clerk 集成

¥2.2. Configure Astro with Clerk

Astro 需要配置为使用 Node 适配器进行服务器端渲染 (SSR) 才能与 Clerk 配合使用。更新 astro.config.mjs 文件以包含 Clerk 集成并启用 SSR:

¥Astro needs to be configured for server-side rendering (SSR) with the Node adapter to work with Clerk. Update your astro.config.mjs file to include the Clerk integration and enable SSR:

astro.config.mjs
import { defineConfig } from 'astro/config'
import node from '@astrojs/node'
import clerk from '@clerk/astro'

export default defineConfig({
integrations: [clerk()],
adapter: node({ mode: 'standalone' }),
output: 'server',
})

2.3.设置 Clerk 中间件

¥2.3. Set up Clerk middleware

clerkMiddleware 辅助函数支持整个应用的身份验证。在 src 目录中创建 middleware.ts 文件:

¥The clerkMiddleware helper enables authentication across your entire application. Create a middleware.ts file in the src directory:

src/middleware.ts
import { clerkMiddleware } from '@clerk/astro/server'

export const onRequest = clerkMiddleware()

2.4.将 Clerk UI 添加到你的页面

¥2.4. Add Clerk UI to your page

更新 src/pages/index.astro 文件以导入 Clerk 身份验证组件:

¥Update your src/pages/index.astro file to import the Clerk authentication components:

src/pages/index.astro
---
import {
SignedIn,
SignedOut,
UserButton,
SignInButton,
} from "@clerk/astro/components";
---

<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
</body>
</html>

现在添加一个带有条件渲染的头部,以便为未认证用户显示登录按钮,为已认证用户显示用户按钮:

¥Now add a header with conditional rendering to show sign-in buttons for unauthenticated users and a user button for authenticated users:

src/pages/index.astro
---
import {
SignedIn,
SignedOut,
UserButton,
SignInButton,
} from "@clerk/astro/components";
---

<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<header>
<SignedOut>
<SignInButton mode="modal" />
</SignedOut>
<SignedIn>
<UserButton />
</SignedIn>
</header>
</body>
</html>

3. 安装和配置 Prisma

¥ Install and configure Prisma

3.1.安装依赖

¥3.1. Install dependencies

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

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

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
信息

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

¥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 the database like "My Clerk Astro Project"

这将造成:

¥This will create:

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

    ¥A prisma/ directory with a schema.prisma file

  • 包含 Prisma 配置的 prisma.config.ts 文件

    ¥A prisma.config.ts file with your Prisma configuration

  • 一个已设置 DATABASE_URL.env 文件

    ¥A .env file with a DATABASE_URL already set

3.2.定义 Prisma Schema

¥3.2. Define your Prisma Schema

添加一个 User 模型,用于存储来自 Clerk 的已认证用户信息。clerkId 字段将每个数据库用户唯一地链接到其 Clerk 账户:

¥Add a User model that will store authenticated user information from Clerk. The clerkId field uniquely links each database user to their Clerk account:

prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}

datasource db {
provider = "postgresql"
}

model User {
id Int @id @default(autoincrement())
clerkId String @unique
email String @unique
name String?
}

运行以下命令创建数据库表:

¥Run the following command to create the database tables:

npx prisma migrate dev --name init

迁移完成后,生成 Prisma 客户端:

¥After the migration is complete, generate the Prisma Client:

npx prisma generate

此操作会在 src/generated/prisma 目录中生成 Prisma 客户端。

¥This generates the Prisma Client in the src/generated/prisma directory.

3.3.创建 TypeScript 环境定义

¥3.3. Create TypeScript environment definitions

src 目录中创建一个 env.d.ts 文件,用于提供环境变量的 TypeScript 定义:

¥Create an env.d.ts file in your src directory to provide TypeScript definitions for your environment variables:

touch src/env.d.ts

为你的应用使用的所有环境变量添加类型定义:

¥Add type definitions for all the environment variables your application uses:

src/env.d.ts
interface ImportMetaEnv {
readonly DATABASE_URL: string;
readonly CLERK_WEBHOOK_SIGNING_SECRET: string;
readonly CLERK_SECRET_KEY: string;
readonly PUBLIC_CLERK_PUBLISHABLE_KEY: string;
}

interface ImportMeta {
readonly env: ImportMetaEnv;
}

3.4.创建一个可复用的 Prisma 客户端

¥3.4. Create a reusable Prisma Client

src 目录中,创建 lib 目录并在其中创建一个 prisma.ts 文件:

¥In the src directory, create a lib directory and a prisma.ts file inside it:

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

使用 PostgreSQL 适配器初始化 Prisma 客户端:

¥Initialize the Prisma Client with the PostgreSQL adapter:

src/lib/prisma.ts
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
connectionString: import.meta.env.DATABASE_URL,
});

const prisma = new PrismaClient({
adapter,
});

export default prisma;

4. 将 Clerk 连接到数据库

¥ Wire Clerk to the database

4.1.创建 Clerk webhook 端点

¥4.1. Create a Clerk webhook endpoint

Webhooks 允许 Clerk 在事件发生时(例如用户注册时)通知你的应用。你将创建一个 API 路由来处理这些 Webhook 并将用户数据同步到你的数据库。

¥Webhooks allow Clerk to notify your application when events occur, such as when a user signs up. You'll create an API route to handle these webhooks and sync user data to your database.

创建 webhook 端点的目录结构和文件:

¥Create the directory structure and file for the webhook endpoint:

mkdir -p src/pages/api/webhooks
touch src/pages/api/webhooks/clerk.ts

导入必要的依赖:

¥Import the necessary dependencies:

src/pages/api/webhooks/clerk.ts
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

创建 Clerk 将调用的 POST 处理程序。verifyWebhook 函数使用签名密钥验证请求是否确实来自 Clerk:

¥Create the POST handler that Clerk will call. The verifyWebhook function validates that the request actually comes from Clerk using the signing secret:

src/pages/api/webhooks/clerk.ts
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const POST: APIRoute = async ({ request }) => {
try {
const evt = await verifyWebhook(request, {
signingSecret: import.meta.env.CLERK_WEBHOOK_SIGNING_SECRET,
});
const { id } = evt.data;
const eventType = evt.type;
console.log(
`Received webhook with ID ${id} and event type of ${eventType}`,
);
} catch (err) {
console.error("Error verifying webhook:", err);
return new Response("Error verifying webhook", { status: 400 });
}
};

创建新用户时,需要将其存储在数据库中。

¥When a new user is created, they need to be stored in the database.

你将通过检查事件类型是否为 user.created 来实现这一点,然后使用 Prisma 的 upsert 方法在用户不存在的情况下创建新用户:

¥You'll do that by checking if the event type is user.created and then using Prisma's upsert method to create a new user if they don't exist:

src/pages/api/webhooks/clerk.ts
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const POST: APIRoute = async ({ request }) => {
try {
const evt = await verifyWebhook(request, {
signingSecret: import.meta.env.CLERK_WEBHOOK_SIGNING_SECRET,
});
const { id } = evt.data;
const eventType = evt.type;
console.log(
`Received webhook with ID ${id} and event type of ${eventType}`,
);

if (eventType === "user.created") {
const { id, email_addresses, first_name, last_name } = evt.data;
await prisma.user.upsert({
where: { clerkId: id },
update: {},
create: {
clerkId: id,
email: email_addresses[0].email_address,
name: `${first_name} ${last_name}`,
},
});
}
} catch (err) {
console.error("Error verifying webhook:", err);
return new Response("Error verifying webhook", { status: 400 });
}
};

最后,向 Clerk 返回响应以确认已收到 webhook:

¥Finally, return a response to Clerk to confirm the webhook was received:

src/pages/api/webhooks/clerk.ts
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const POST: APIRoute = async ({ request }) => {
try {
const evt = await verifyWebhook(request, {
signingSecret: import.meta.env.CLERK_WEBHOOK_SIGNING_SECRET,
});
const { id } = evt.data;
const eventType = evt.type;
console.log(
`Received webhook with ID ${id} and event type of ${eventType}`,
);

if (eventType === "user.created") {
const { id, email_addresses, first_name, last_name } = evt.data;
await prisma.user.upsert({
where: { clerkId: id },
update: {},
create: {
clerkId: id,
email: email_addresses[0].email_address,
name: `${first_name} ${last_name}`,
},
});
}

return new Response("Webhook received", { status: 200 });
} catch (err) {
console.error("Error verifying webhook:", err);
return new Response("Error verifying webhook", { status: 400 });
}
};

4.2.向 Webhook 公开本地应用

¥4.2. Expose your local app for webhooks

你需要使用 ngrok 为 webhook 公开本地应用。这将允许 Clerk 访问你的 /api/webhooks/clerk 路由以推送类似 user.created 的事件。

¥You'll need to expose your local app for webhooks with ngrok. This will allow Clerk to reach your /api/webhooks/clerk route to push events like user.created.

启动你的开发服务器:

¥Start your development server:

npm run dev

在另一个终端窗口中,全局安装 ngrok 并暴露你的本地应用:

¥In a separate terminal window, install ngrok globally and expose your local app:

npm install --global ngrok
ngrok http 4321

复制 ngrok Forwarding URL(例如,https://a65a60261342.ngrok-free.app)。这将用于在 Clerk 中配置 webhook URL。

¥Copy the ngrok Forwarding URL (e.g., https://a65a60261342.ngrok-free.app). This will be used to configure the webhook URL in Clerk.

4.3.配置 Astro 以允许 ngrok 连接

¥4.3. Configure Astro to allow ngrok connections

Astro 需要配置为接受来自 ngrok 域的连接。更新 astro.config.mjs 文件以包含 ngrok 主机在允许的主机列表中:

¥Astro needs to be configured to accept connections from the ngrok domain. Update your astro.config.mjs to include the ngrok host in the allowed hosts list:

astro.config.mjs
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import clerk from "@clerk/astro";

export default defineConfig({
integrations: [clerk()],
adapter: node({ mode: "standalone" }),
output: "server",
server: {
allowedHosts: ["localhost", "<your-ngrok-subdomain>.ngrok-free.app"],
},
});
注意

<your-ngrok-subdomain> 替换为你的 ngrok URL 中的子域名。例如,如果你的 ngrok URL 为 https://a65a60261342.ngrok-free.app,则使用 a65a60261342.ngrok-free.app

¥Replace <your-ngrok-subdomain> with the subdomain from your ngrok URL. For example, if your ngrok URL is https://a65a60261342.ngrok-free.app, use a65a60261342.ngrok-free.app.

4.4.在 Clerk 中注册 Webhook

¥4.4. Register the webhook in Clerk

导航到 Clerk 应用的“Webhooks”部分,该部分位于“开发者”下“配置”选项卡的底部附近。

¥Navigate to the Webhooks section of your Clerk application located near the bottom of the Configure tab under Developers.

点击“添加端点”,将 ngrok URL 粘贴到“端点 URL”字段中,并在末尾添加 /api/webhooks/clerk。它应该类似于以下内容:

¥Click Add Endpoint and paste the ngrok URL into the Endpoint URL field and add /api/webhooks/clerk to the end. It should look similar to this:

https://a65a60261342.ngrok-free.app/api/webhooks/clerk

在“消息过滤”下,选中“user.created”事件旁边的复选框,即可订阅该事件。

¥Subscribe to the user.created event by checking the box next to it under Message Filtering.

点击“创建”保存 Webhook 端点。

¥Click Create to save the webhook endpoint.

复制签名密钥并将其添加到你的 .env 文件中:

¥Copy the Signing Secret and add it to your .env file:

.env
# Prisma
DATABASE_URL=<your-database-url>

# Clerk
PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>
CLERK_WEBHOOK_SIGNING_SECRET=<your-signing-secret>

重启开发服务器以应用新的环境变量:

¥Restart your dev server to pick up the new environment variable:

npm run dev

4.5.测试集成

¥4.5. Test the integration

在浏览器中访问 http://localhost:4321,并使用你在 Clerk 中配置的任何注册选项登录。

¥Navigate to http://localhost:4321 in your browser and sign in using any of the sign-up options you configured in Clerk.

打开 Prisma Studio,验证用户是否已在数据库中创建:

¥Open Prisma Studio to verify that the user was created in your database:

npx prisma studio

你应该看到一条包含你注册时提供的 Clerk ID、电子邮件和名称的新用户记录。

¥You should see a new user record with the Clerk ID, email, and name from your sign-up.

注意

如果你没有看到用户记录,请检查以下几点:

¥If you don't see a user record, there are a few things to check:

  • 从 Clerk 的“用户”选项卡中删除你的用户,然后尝试重新注册。

    ¥Delete your user from the Users tab in Clerk and try signing up again.

  • 检查你的 ngrok URL 并确保其正确(每次重启 ngrok 时,URL 都会更改)。

    ¥Check your ngrok URL and ensure it's correct (it will change every time you restart ngrok).

  • 验证你的 Clerk Webhook 是否指向正确的 ngrok URL。

    ¥Verify your Clerk webhook is pointing to the correct ngrok URL.

  • 请确保已将 /api/webhooks/clerk 添加到 webhook URL 的末尾。

    ¥Make sure you've added /api/webhooks/clerk to the end of the webhook URL.

  • 确保你已在 Clerk 中订阅了 user.created 事件。

    ¥Ensure you've subscribed to the user.created event in Clerk.

  • 确认你已在 astro.config.mjs 中将 ngrok 主机添加到 allowedHosts,并移除 https://

    ¥Confirm you've added the ngrok host to allowedHosts in astro.config.mjs and removed https://.

  • 检查运行 npm run dev 的终端是否有任何错误消息。

    ¥Check the terminal running npm run dev for any error messages.

你已成功构建了一个使用 Clerk 身份验证和 Prisma 的 Astro 应用,为构建一个安全且可扩展的全栈应用奠定了基础,该应用可以轻松处理用户管理和数据持久性。

¥You've successfully built an Astro application with Clerk authentication and Prisma, creating a foundation for a secure and scalable full-stack application that handles user management and data persistence with ease.

下一步

¥Next steps

现在你已经拥有一个运行正常的 Astro 应用,该应用已启用 Clerk 身份验证并连接到 Prisma Postgres 数据库,你可以:

¥Now that you have a working Astro app with Clerk authentication and Prisma connected to a Prisma Postgres database, you can:

  • 添加用户配置文件管理和更新功能

    ¥Add user profile management and update functionality

  • 构建需要身份验证的受保护 API 路由

    ¥Build protected API routes that require authentication

  • 使用与用户相关的其他模型扩展你的模式

    ¥Extend your schema with additional models related to users

  • 部署到你首选的托管平台,并在 Clerk 中设置你的生产 Webhook URL

    ¥Deploy to your preferred hosting platform and set your production webhook URL in Clerk

  • 使用 Prisma Postgres 启用查询缓存以获得更好的性能

    ¥Enable query caching with Prisma Postgres for better performance

更多信息

¥More info


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!