【Cloudflare Workers 全端架構師之路 06】安全篇:守門員 Middleware、CORS 與 JWT 驗證
01. 前言:為什麼要在 Edge 做安全防護?
在傳統架構中,請求通常要穿過 Load Balancer、進入 Web Server、啟動 Application Runtime (如 Node.js),最後才在 Controller 層被 AuthMiddleware 擋下來。這浪費了大量的運算資源。
在 Cloudflare Workers 架構下,我們可以把這道防線推到最前線:
- 驗證 Token: 如果 JWT 無效,直接在邊緣回傳 401,完全不觸發 D1 或 R2。
- 阻擋攻擊: 如果 IP 在黑名單,直接斷開連線。
這就是 「將安全性左移 (Shift Security Left)」 到網路邊緣的概念。
02. Hono Middleware 機制
Hono 的核心是基於 洋蔥模型 (Onion Model) 的 Middleware 機制,這跟 Koa 或 Express 很像。
// Middleware 範例
app.use('*', async (c, next) => {
const start = Date.now();
await next(); // 進入下一個 Middleware 或主要邏輯
const end = Date.now();
c.header('X-Response-Time', `${end - start}ms`);
})
03. 實作:搞定 CORS (跨來源資源共用)
做前後端分離開發時,CORS (Cross-Origin Resource Sharing) 是最常見的惡夢。瀏覽器會先發送一個 OPTIONS 請求 (Preflight) 來詢問權限。
在 Workers 中處理 CORS 非常簡單且高效,因為 OPTIONS 請求可以在邊緣極速回應,幾乎不消耗成本。
import { Hono } from 'hono'
import { cors } from 'hono/cors'
const app = new Hono()
// 全域套用 CORS
app.use('/*', cors({
origin: ['[https://your-frontend.com](https://your-frontend.com)', 'http://localhost:3000'], // 限制來源
allowMethods: ['POST', 'GET', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization'],
exposeHeaders: ['Content-Length'],
maxAge: 600, // 告訴瀏覽器:這個設定快取 10 分鐘,別一直問
credentials: true,
}))
app.get('/', (c) => c.text('CORS is enabled!'))
04. 深度實作:JWT 身分驗證
我們不希望每次驗證使用者都要去查資料庫 (D1)。JWT (JSON Web Token) 是無狀態驗證的最佳解。我們將使用 hono/jwt 中介軟體。
步驟 1: 設定密鑰
# 生成一個隨機密鑰並存入 Cloudflare Secrets
openssl rand -hex 32
npx wrangler secret put JWT_SECRET
步驟 2: 實作登入 (簽發 Token) 與 驗證 (保護路由)
修改 src/index.ts:
import { Hono } from 'hono'
import { jwt, sign } from 'hono/jwt'
type Bindings = {
JWT_SECRET: string;
}
const app = new Hono<{ Bindings: Bindings }>()
// 1. 公開路由:登入並取得 Token
app.post('/auth/login', async (c) => {
const { username, password } = await c.req.json();
// (這裡省略真實的密碼驗證邏輯,請查 D1 比對 hash)
if (username === 'admin' && password === 'password') {
const payload = {
sub: username,
role: 'admin',
exp: Math.floor(Date.now() / 1000) + 60 * 60, // 1小時過期
}
const token = await sign(payload, c.env.JWT_SECRET)
return c.json({ token })
}
return c.json({ error: 'Unauthorized' }, 401)
})
// 2. 保護路由:使用 JWT Middleware
// 只有 /api/* 開頭的路徑需要驗證
app.use('/api/*', (c, next) => {
const jwtMiddleware = jwt({
secret: c.env.JWT_SECRET,
})
return jwtMiddleware(c, next)
})
// 3. 存取受保護資源
app.get('/api/profile', (c) => {
// Hono 會自動把解碼後的 payload 放在 c.get('jwtPayload')
const payload = c.get('jwtPayload')
return c.json({
message: `Hello, ${payload.sub}!`,
yourRole: payload.role
})
})
export default app
05. 進階防護:簡易 Rate Limiting (速率限制)
為了防止 API 被惡意刷爆,我們可以利用 Workers KV 實作一個簡單的計數器。雖然這不是精確的原子操作 (Atomic),但對於防護 DDoS 已經足夠有效。
(註:若需精確控制,建議使用 Cloudflare 官方的 Rate Limiting 產品或 Durable Objects)
import { Hono } from 'hono'
type Bindings = {
KV: KVNamespace; // 記得在 wrangler.toml 綁定 KV
}
const app = new Hono<{ Bindings: Bindings }>()
// Rate Limiter Middleware
app.use('*', async (c, next) => {
const ip = c.req.header('CF-Connecting-IP') || 'unknown';
const key = `rate_limit:${ip}`;
// 讀取當前次數
const countStr = await c.env.KV.get(key);
let count = countStr ? parseInt(countStr) : 0;
if (count >= 100) { // 限制每分鐘 100 次
return c.text('Too Many Requests', 429);
}
// 增加次數並設定 60 秒過期
// 注意:這不是原子操作,在高併發下可能會少算,但作為防護已足夠
await c.env.KV.put(key, (count + 1).toString(), { expirationTtl: 60 });
await next();
})
06. 最佳實踐:環境隔離
在處理安全性時,切記不要把測試環境的 Token 用在正式環境。
利用 wrangler.toml 的 Environments 功能來隔離:
# wrangler.toml (Production)
[vars]
API_URL = "[https://api.myapp.com](https://api.myapp.com)"
# 開發環境 (Development)
[env.dev]
name = "my-api-dev"
[env.dev.vars]
API_URL = "http://localhost:8787"
執行時:
npm run deploy-> 部署到 Productionnpm run deploy -- --env dev-> 部署到 Dev 環境
07. 小結與下一步
我們現在擁有了一個:
- 安全:有 JWT 保護與 CORS 設定。
- 抗壓:有基本的 Rate Limiting。
- 高效:所有驗證都在 Edge 完成,不浪費後端資料庫資源。
目前的架構雖然安全,但每個請求都是「獨立」的。如果我們需要做一個即時聊天室,或者需要保證庫存扣減的絕對順序性,目前的 Stateless 架構是做不到的。
我們需要一個「有狀態」且「強一致性」的地方。
在下一篇 Part 7: 狀態篇,我們將召喚 Cloudflare 的獨門黑科技 —— Durable Objects。這將是你從「Web 開發者」跨越到「分散式系統工程師」的關鍵門檻。

關於作者
Ken Huang
熱衷於嘗試各類新技術的軟體開發者,現階段主力為 Android / iOS 雙平台開發,同時持續深耕前端與後端技術,以成為全端工程師與軟體架構師為目標。
最廣為人知的代表作為 BePTT。開發哲學是「以做身體健康為前提」,致力於在工作與生活平衡的基礎上,打造出擁有絕佳使用體驗的軟體服務。
這裡是用於紀錄與分享開發經驗的空間,希望能透過我的實戰筆記,幫助開發者解決疑難雜症並提升效率。
系列文章目錄
- 【Cloudflare Workers 全端架構師之路 04】數據篇:D1 資料庫設計模式與效能優化
- 【Cloudflare Workers 全端架構師之路 05】儲存篇:R2 檔案處理與零流量費架構
- 【Cloudflare Workers 全端架構師之路 06】安全篇:守門員 Middleware、CORS 與 JWT 驗證 (本文)
- 【Cloudflare Workers 全端架構師之路 07】狀態篇:Durable Objects 深度解析與 WebSocket 叢集
- 【Cloudflare Workers 全端架構師之路 08】非同步篇:使用 Queues 解耦系統與背景任務