架構決策分析:Admin Dashboard 身份驗證模型
NextAuth (BFF 代理) vs. 純 SPA (Hono JWT 直連)
1. 前言:核心命題
在構建基於 Cloudflare Workers / Hono 的後端,並搭配現代前端(Next.js 或 Vite)開發 Admin Dashboard 時,我們面臨一個經典的架構選擇:
應該依賴成熟的 NextAuth (Auth.js) 在前端層處理完登入,後端僅透過 Shared Secret 信任前端?還是應該讓後端 Hono 直接實作完整的 JWT 驗證體系,讓前端回歸純 SPA 模式?
這不僅是開發便利性的選擇,更是「資安防禦縱深(Defense in Depth)」與「實作風險(Implementation Risk)」之間的權衡。
2. 方案 A:BFF 代理模式 (Current Plan)
架構: Next.js App Router (Admin) + NextAuth ↔ Hono API (Workers)
在此模式中,Next.js 扮演了 BFF (Backend for Frontend) 的角色。
運作流程
- User ↔ Next.js:使用者在 Next.js 端透過 NextAuth 登入(使用 HttpOnly Cookie 維持 Session)。
- Next.js ↔ Hono API:當 Admin 需要數據時,Next.js 後端 API Route 取出
VERCEL_SECRET,以Authorization: Bearer <SECRET>呼叫 Hono API。 - Hono API:檢查 Secret 是否吻合。若吻合,視為「受信賴的 Admin 請求」,放行所有權限。
安全性分析
-
優點(Web Security):
- 抗 CSRF/XSS 健壯性高:NextAuth 自動處理了 Session Cookie 的 SameSite、HttpOnly 等屬性,並內建 CSRF Token 機制。這是業界經過驗證的成熟實作,能大幅降低瀏覽器端的攻擊面。
- 開發速度快:不需要手寫 OAuth callback、Session 儲存、密碼重設等繁瑣流程。
-
缺點(Backend Security):
- 依賴單一信任點 (Single Point of Failure):Hono API 認的是一把
Shared Secret。這意味著一旦這把 Key 外洩(日誌、監控、誤傳 Repo),攻擊者即可繞過所有前端驗證,直接對 API 發起「上帝模式」的請求。 - 違反最小權限原則 (Least Privilege):API 無法區分發送請求的是 "Super Admin" 還是 "Content Editor"。對於 API 來說,所有請求都是「同一個 Admin」。
- 審計困難 (Lack of Auditability):在 API Access Log 中,你只能看到請求來自 Next.js Server,無法追溯是「哪一位具體的操作人員」刪除了資料。
- 依賴單一信任點 (Single Point of Failure):Hono API 認的是一把
3. 方案 B:直連驗證模式 (Alternative)
架構: Vite SPA (React) ↔ Hono API (JWT)
在此模式中,前端是靜態的(Static Assets),所有安全性邏輯下沉至 Hono 後端。
運作流程
- User ↔ Hono API:前端 POST
/api/login,Hono 驗證帳密後簽發 JWT (JSON Web Token)。 - Token 儲存:前端將 JWT 存放在記憶體(最安全但重整會掉)或 HttpOnly Cookie(需配合 CSRF 防護)。
- Request:前端每次呼叫 API 時帶上 Token。
- Hono API:驗證 JWT 簽章有效性、過期時間、以及 Payload 中的
role欄位,決定是否放行。
安全性分析
-
優點(Architecture Security):
- 細粒度權限控制 (Granular Access Control):API 知道「現在是誰 (Who)」以及「他是什麼角色 (Role)」。可以輕易實作
if (user.role !== 'admin') return 403。 - 爆炸半徑小 (Limited Blast Radius):若某個 Admin 的 Token 被盜,攻擊者只能在該 Token 的有效期內、以該使用者的權限操作。這比 Shared Secret 外洩導致「全站淪陷」的風險低得多。
- 可審計與撤銷:可以記錄具體操作者;若發現異常,可以透過黑名單或縮短 Token 效期來阻斷攻擊。
- 收斂攻擊面:
VERCEL_SECRET不再用於常規業務,僅限於內部系統(如 Cron Job)互連,大幅降低外洩機率。
- 細粒度權限控制 (Granular Access Control):API 知道「現在是誰 (Who)」以及「他是什麼角色 (Role)」。可以輕易實作
-
缺點(Implementation Risk):
- 自造輪子的風險 (Reinventing the Wheel):開發者需自行處理密碼雜湊 (Argon2/Bcrypt)、JWT 簽發與輪替 (Refresh Token)、黑名單機制。任何一個環節實作錯誤(例如 JWT 演算法設為 None、Secret 太弱、Token 存在 LocalStorage 被 XSS 竊取),都會導致嚴重漏洞。
- 複雜度上升:需要在 Hono 內實作完整的 Auth Middleware。
4. 深度對決:該如何選擇?
我們可以從兩個維度來評估:「理想的安全模型」 與 「現實的實作風險」。
維度一:後端保護力 (Backend Protection)
勝出者:方案 B (Hono JWT)
從 CISSP 或資安架構的角度來看,依賴 Shared Secret 是架構上的「壞味道 (Smell)」。它假設了內網或 Server-to-Server 的連線是絕對安全的,這不符合 Zero Trust(零信任)原則。
方案 B 要求每個 Request 都必須自我證明身份(Per-request Authentication),這是更健壯的模型。
維度二:人為錯誤風險 (Human Error & Implementation)
勝出者:方案 A (NextAuth)
安全不僅是理論,更是實踐。Auth.js (NextAuth) 是由數千名開發者維護的開源專案,其對抗 Session Fixation、Timing Attack 等攻擊的防禦能力,通常遠高於單一開發者在兩週內手刻的程式碼。
如果你的團隊對 JWT 的最佳實踐(例如:不存 LocalStorage、設定極短效期、處理 Refresh Token Rotation)沒有十足把握,方案 B 反而可能因為實作漏洞而比方案 A 更不安全。
5. 結論與建議
綜合評估
- 安全性上限:方案 B (JWT) > 方案 A (Shared Secret)
- 安全性下限(防呆):方案 A (NextAuth) > 方案 B (JWT)
- 開發維護成本:方案 A (低) < 方案 B (高)
最終建議 (The Verdict)
如果你是為了快速迭代產品,且團隊規模較小:
請選擇 方案 A (NextAuth)。利用現成的安全框架保護前端 Session 是最高效的策略。
但為了修補 Shared Secret 的架構缺陷,建議採取「混合增強策略」:
不要只依賴靜態的 Shared Secret。你可以在 Next.js 後端呼叫 Hono 時,將 NextAuth 的 Session 資訊「封裝」進去:
- Next.js 端:取得使用者 Session 後,用一個 Server-Side Key 簽署一個短效期的 JWT(包含 user_id, role),放在 Header 發給 Hono。
- Hono 端:不再只認固定的字串,而是驗證這個 Server-to-Server 的 JWT。
這樣你既保留了 NextAuth 在前端的便利與防護,又在後端實現了基於使用者身份的細粒度權限控制,同時避免了靜態 Secret 一處外洩全站崩潰的風險。
一句話總結:
如果追求架構完美與最小權限,Hono JWT 是正解;但若考量開發資源與避免「手滑」寫出漏洞,NextAuth 是更務實的防線,只要記得別讓你的 Shared Secret 變成永遠不換的萬能鑰匙。