如何在 Clerk Auth 和 Astro 中使用 Prisma ORM
介绍
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 文件中。
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
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 文件
import { clerkMiddleware } from '@clerk/astro/server'
export const onRequest = clerkMiddleware()
2.4. 将 Clerk UI 添加到您的页面
更新您的 src/pages/index.astro 文件以导入 Clerk 身份验证组件
---
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>
现在添加一个带有条件渲染的头部,用于向未经验证的用户显示登录按钮,并向已验证的用户显示用户按钮
---
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 账户唯一链接
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
为应用程序使用的所有环境变量添加类型定义
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 客户端
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
导入必要的依赖项
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";
创建 Clerk 将调用的 POST 处理程序。verifyWebhook 函数使用签名密钥验证请求是否确实来自 Clerk
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 方法在用户不存在时创建新用户来完成此操作
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 已接收
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 主机包含在允许主机列表中
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 文件中
# 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.mjs的allowedHosts中添加了 ngrok 主机并删除了https://。 - 检查运行
npm run dev的终端是否有任何错误消息。
您已成功构建了一个具有 Clerk 身份验证和 Prisma 的 Astro 应用程序,为安全且可扩展的全栈应用程序奠定了基础,该应用程序可轻松处理用户管理和数据持久性。
后续步骤
现在您已经拥有一个正常工作的 Astro 应用程序,其中包含 Clerk 身份验证和连接到 Prisma Postgres 数据库的 Prisma,您可以
- 添加用户资料管理和更新功能
- 构建需要身份验证的受保护 API 路由
- 使用与用户相关的其他模型扩展您的架构
- 部署到您首选的托管平台并在 Clerk 中设置您的生产 webhook URL
- 使用 Prisma Postgres 启用查询缓存以获得更好的性能
更多信息
与 Prisma 保持联系
通过以下方式与我们保持联系,继续你的 Prisma 之旅: 我们的活跃社区。保持信息灵通,参与其中,并与其他开发人员协作。
- 在 X 上关注我们 获取公告、直播活动和实用技巧。
- 加入我们的 Discord 提问、与社区交流,并通过对话获得积极支持。
- 在 YouTube 上订阅 获取教程、演示和直播。
- 在 GitHub 上参与 加星收藏存储库、报告问题或为问题做出贡献。