跳至主要内容

如何在 Clerk Auth 和 Astro 中使用 Prisma ORM

25 分钟

介绍

Clerk 是一个即插即用的身份验证提供商,它负责注册、登录、用户管理和 webhook,因此您无需自己处理。

在本指南中,您将把 Clerk 连接到一个全新的 Astro 应用程序中,并将用户持久化到 Prisma Postgres 数据库中。您可以在 GitHub 上找到本指南的完整示例。

先决条件

1. 设置项目

创建一个新的 Astro 项目

npm create astro@latest

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

信息
  • 您想如何启动新项目? Empty
  • 安装依赖项? Yes
  • 初始化新的 Git 存储库? Yes

进入新创建的项目目录

cd <your-project-name>

2. 设置 Clerk

2.1. 创建新的 Clerk 应用程序

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

信息

在本指南中,将使用 Google、Github 和 Email 登录选项。

安装 Clerk Astro SDK 和 Node 适配器

npm install @clerk/astro @astrojs/node

在 Clerk 控制台中,导航到API 密钥页面。在快速复制部分,复制您的 Clerk 可发布密钥和秘密密钥。将您的密钥粘贴到项目根目录下的 .env 文件中。

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

2.2. 使用 Clerk 配置 Astro

Astro 需要配置为使用 Node 适配器进行服务器端渲染 (SSR) 才能与 Clerk 配合使用。更新您的 astro.config.mjs 文件以包含 Clerk 集成并启用 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 中间件

clerkMiddleware 辅助函数可以在整个应用程序中启用身份验证。在 src 目录中创建一个 middleware.ts 文件

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

export const onRequest = clerkMiddleware()

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

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

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>

现在添加一个带有条件渲染的头部,用于向未经验证的用户显示登录按钮,并向已验证的用户显示用户按钮

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

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

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

这将创建

  • 一个包含 schema.prisma 文件的 prisma/ 目录
  • 一个包含 Prisma 配置的 prisma.config.ts 文件
  • 一个已设置 DATABASE_URL.env 文件

3.2. 定义您的 Prisma 架构

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

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?
}

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

npx prisma migrate dev --name init

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

npx prisma generate

这将在 src/generated/prisma 目录中生成 Prisma 客户端。

3.3. 创建 TypeScript 环境定义

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

touch src/env.d.ts

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

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 客户端

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

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

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

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 连接到数据库

4.1. 创建 Clerk webhook 端点

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

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

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

导入必要的依赖项

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

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 });
}
};

当创建新用户时,他们需要存储在数据库中。

您可以通过检查事件类型是否为 user.created,然后使用 Prisma 的 upsert 方法在用户不存在时创建新用户来完成此操作

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 已接收

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

您需要使用 ngrok 暴露您的本地应用程序以用于 webhook。这将允许 Clerk 访问您的 /api/webhooks/clerk 路由以推送 user.created 等事件。

启动您的开发服务器

npm run dev

在单独的终端窗口中,全局安装 ngrok 并暴露您的本地应用程序

npm install --global ngrok
ngrok http 4321

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

4.3. 配置 Astro 以允许 ngrok 连接

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

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

4.4. 在 Clerk 中注册 webhook

导航到 Clerk 应用程序的“Webhooks”部分,该部分位于“Configure”选项卡下“Developers”部分的底部。

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

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

通过勾选“消息过滤”下的复选框来订阅 user.created 事件。

点击 创建 以保存 webhook 端点。

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

.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>

重新启动您的开发服务器以获取新的环境变量

npm run dev

4.5. 测试集成

在浏览器中导航到 https://:4321,并使用您在 Clerk 中配置的任何注册选项登录。

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

npx prisma studio

您应该看到一个新的用户记录,其中包含您的注册信息中的 Clerk ID、电子邮件和姓名。

注意

如果您没有看到用户记录,有几点需要检查

  • 从 Clerk 的“用户”选项卡中删除您的用户,然后再次尝试注册。
  • 检查您的 ngrok URL 并确保其正确(每次重新启动 ngrok 时都会更改)。
  • 验证您的 Clerk webhook 是否指向正确的 ngrok URL。
  • 确保您已在 webhook URL 的末尾添加 /api/webhooks/clerk
  • 确保您已在 Clerk 中订阅 user.created 事件。
  • 确认您已在 astro.config.mjsallowedHosts 中添加了 ngrok 主机并删除了 https://
  • 检查运行 npm run dev 的终端是否有任何错误消息。

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

后续步骤

现在您已经拥有一个正常工作的 Astro 应用程序,其中包含 Clerk 身份验证和连接到 Prisma Postgres 数据库的 Prisma,您可以

  • 添加用户资料管理和更新功能
  • 构建需要身份验证的受保护 API 路由
  • 使用与用户相关的其他模型扩展您的架构
  • 部署到您首选的托管平台并在 Clerk 中设置您的生产 webhook URL
  • 使用 Prisma Postgres 启用查询缓存以获得更好的性能

更多信息


与 Prisma 保持联系

通过以下方式与我们保持联系,继续你的 Prisma 之旅: 我们的活跃社区。保持信息灵通,参与其中,并与其他开发人员协作。

我们真诚地感谢你的参与,并期待你成为我们社区的一部分!

© . This site is unofficial and not affiliated with Prisma Data, Inc.