如何使用 Prisma ORM 搭配 Clerk Auth 及 Astro
簡介
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 keys 頁面。在 Quick Copy 區段中,複製您的 Clerk Publishable Key 與 Secret Key。將這些金鑰貼上到專案根目錄下的 .env 檔案中。
PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>
2.2. 配置 Astro 與 Clerk
Astro 需要配置伺服器端渲染 (SSR) 並使用 Node 轉接器才能與 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 中介軟體 (Middleware)
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 資料庫時,您需要回答幾個問題。請選擇最接近您所在位置的區域,並為資料庫取一個好記的名字,例如「My Clerk Astro Project」。
這將建立:
- 一個包含
schema.prisma檔案的prisma/目錄 - 一個包含您 Prisma 配置的
prisma.config.ts檔案。 - 一個已設定好
DATABASE_URL的.env檔案
3.2. 定義您的 Prisma Schema
加入一個 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 Client。
npx prisma generate
這會在 src/generated/prisma 目錄下產生 Prisma Client。
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 Client
在 src 目錄中建立 lib 目錄,並在其中建立 prisma.ts 檔案。
mkdir src/lib
touch src/lib/prisma.ts
使用 PostgreSQL 轉接器初始化 Prisma Client。
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 端點
Webhook 允許 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 將您的本機應用程式公開。這將允許 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 區段,該區段位於 Developers 下方的 Configure 頁籤底部附近。
點擊 Add Endpoint,將 ngrok URL 貼上至 Endpoint URL 欄位,並在結尾加上 /api/webhooks/clerk。它看起來應該像這樣。
https://a65a60261342.ngrok-free.app/api/webhooks/clerk
勾選 Message Filtering 下方的 user.created 事件旁邊的核取方塊,以訂閱該事件。
點擊 Create 以儲存 Webhook 端點。
複製 Signing Secret 並將其加入到您的 .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 的 Users 分頁刪除您的使用者,然後再次嘗試註冊。
- 檢查您的 ngrok URL 並確保其正確 (每次重新啟動 ngrok 時它都會變更)。
- 確認您的 Clerk Webhook 指向正確的 ngrok URL。
- 確保您已在 Webhook URL 的末尾加上
/api/webhooks/clerk。 - 確保您已在 Clerk 中訂閱了 user.created 事件。
- 確認您已將 ngrok 主機加入至
astro.config.mjs中的allowedHosts,並且移除了https://。 - 檢查執行
npm run dev的終端機,查看是否有任何錯誤訊息。
您已成功建構了一個搭配 Clerk 驗證與 Prisma 的 Astro 應用程式,為一個安全且可擴充的全端應用程式奠定了基礎,該應用程式能輕鬆處理使用者管理與資料持久化。
後續步驟
現在您已擁有一個搭配 Clerk 驗證且連接至 Prisma Postgres 資料庫的運作中 Astro 應用程式,您可以:
- 加入使用者個人資料管理與更新功能
- 建構需要驗證的受保護 API 路由
- 使用與使用者相關的其他模型來擴充您的 Schema
- 部署至您偏好的託管平台,並在 Clerk 中設定您的正式環境 Webhook URL
- 啟用 Prisma Postgres 的查詢快取以獲得更好的效能
更多資訊
與 Prisma 保持聯繫
透過以下方式與我們聯繫,繼續您的 Prisma 旅程: 我們的活躍社群。保持資訊靈通、參與其中,並與其他開發者合作
- 在 X 上關注我們 以獲取公告、現場活動和實用技巧。
- 加入我們的 Discord 提出問題、與社群對話,並透過對話獲得積極支援。
- 在 YouTube 上訂閱 查看教學、演示和直播。
- 在 GitHub 上交流 透過為存放庫加星標、報告問題或為 issue 做出貢獻。