跳至主要內容

如何使用 Prisma ORM 搭配 Clerk Auth 及 Astro

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 keys 頁面。在 Quick Copy 區段中,複製您的 Clerk Publishable Key 與 Secret Key。將這些金鑰貼上到專案根目錄下的 .env 檔案中。

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

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 中介軟體 (Middleware)

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 資料庫時,您需要回答幾個問題。請選擇最接近您所在位置的區域,並為資料庫取一個好記的名字,例如「My Clerk Astro Project」。

這將建立:

  • 一個包含 schema.prisma 檔案的 prisma/ 目錄
  • 一個包含您 Prisma 配置的 prisma.config.ts 檔案。
  • 一個已設定好 DATABASE_URL.env 檔案

3.2. 定義您的 Prisma Schema

加入一個 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 Client。

npx prisma generate

這會在 src/generated/prisma 目錄下產生 Prisma Client。

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 Client

src 目錄中建立 lib 目錄,並在其中建立 prisma.ts 檔案。

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

使用 PostgreSQL 轉接器初始化 Prisma Client。

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 端點

Webhook 允許 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 將您的本機應用程式公開。這將允許 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 區段,該區段位於 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 檔案中。

.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 旅程: 我們的活躍社群。保持資訊靈通、參與其中,並與其他開發者合作

我們衷心感謝您的參與,並期待您成為我們社群的一份子!

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