1. 「已登入卻認不出我?」(問題的起點)
OAuth2、JWT、Session 認證… 認證方式多種多樣,對大多數情況已足夠。我的經驗也是如此。
- 為自製的 Email 客戶端或 ChatGPT 的 MyGPT 加上 OAuth2 時,彷彿體驗到了真正的使用者體驗
- 完全由 Django 伺服器提供的 Web App,Session 認證 是最佳選擇!
- 前後端分離的架構下,JWT 最為乾淨利落
但是,這些組合在某一刻會同時崩潰。崩潰的關鍵在 非同步工作 (Celery)。使用者點擊按鈕時,後端不直接處理,而是把任務交給遠端的 AI 計算伺服器或 Worker。此時 Worker 會說:
"嗯… 收到請求了,但這是替誰執行的?request.user 不存在啊。"

2. 問題在「後端 ↔ 後端」+「非同步 Worker (Celery)」
我最終決定導入 API Key,根本原因是 後端服務之間的通訊 中 Celery Worker 介入 的架構。
- 使用者發送 Web 請求
- 後端將「任務」放入佇列
- Celery Worker 消費佇列,向某個後端/計算伺服器發送非同步請求
在這個流程中,最痛的地方是:
- Worker 沒有 request.user
- 也沒有 Session(因為不是瀏覽器)
- JWT 更是尷尬(誰在何處、如何管理與傳遞 token)
- OAuth2 完全依賴「使用者互動」的流程,根本不可行
當 JWT 與 Session 失效時,唯一剩下的問題被濃縮為:
「計算伺服器如何得知這個工作屬於哪個客戶(租戶/使用者)?」
3. 在 Worker 世界裡,先要「識別」再談「認證」
Web 請求的流程是「認證=登入」且「登入=使用者」自然相連。 但 Worker 不是人,而是自動借用 CPU 執行任務的應用程式,因而在「認證」之前必須先「識別」:
- 任務必須以 A 客戶的資料執行
- 結果必須存回 A 客戶的資源
- 計費/權限/配額也必須以 A 客戶為基礎扣除
如果硬要把 JWT 或 Session 塞進來,會產生 token 發行、保存、傳遞、過期、重新發行等繁雜設計,甚至會產生「即使是我們自己的客戶,但他不是在瀏覽器操作,後端卻要去取得 JWT?」的強烈違和感。這種想法我立刻棄用。
4. 解決方案:API Key 在此環節既簡單又有力
於是我採用了 API Key,問題瞬間迎刃而解。
- Worker 在內部請求時,只需在 Header 加上一行即可同時完成認證與識別
- 伺服器看到這把鍵後,立即 映射到對應的使用者/客戶
- 鍵的撤銷或輪換也變得非常清晰
例如,伺服器向計算伺服器發送非同步請求的樣子如下:
POST /v1/ai/jobs
Authorization: Api-Key <KEY>
Content-Type: application/json
{ "job_id": "...", "payload": {...} }
Worker 不需要 request.user,只要把上述請求發出去,接收端即可依照說明使用 API Key 來辨識使用者。
5. 關鍵改進:將 API Key 與 USER 直接綁定,運維更輕鬆
我特別滿意的地方在於此。
傳統的 rest_framework_api_key 僅提供鍵本身,而我的需求是 「鍵 ↔ 使用者(客戶) 的結合」。因此我繼承 AbstractAPIKey,建立 CustomAPIKey,並以 FK 連結到 AUTH_USER 模型。
結果相當令人滿意。
from django.conf import settings
from rest_framework_api_key.models import AbstractAPIKey
from django.db import models
class CustomAPIKey(AbstractAPIKey):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="api_keys"
)
is_test = models.BooleanField(default=False) # 區分測試/正式鍵
如此一來,除了「認證」之外,還能開啟一系列 運營功能。
6. 為每位使用者自動發放鍵帶來的運營收益
在使用者註冊時自動為其生成一把鍵,讓以下工作變得非常便利。
1) 易於管理有效性
- 可直接查詢、停用或刪除特定使用者的鍵
- 使用者刪除時,FK cascade 會自動清除相關鍵
2) 鍵輪換更簡單
- 發現鍵可能外洩時,只需發新鍵、廢除舊鍵即可
- 支援多把鍵同時存在,實現 無停機替換
3) 計費/配額/權限以使用者為單位
- 不必再額外推斷「這把 API Key 屬於誰」
- 直接以使用者為基礎套用計費與限制
4) 同一使用者可擁有多把鍵
is_test 旗標在此派上用場。因為 API Key 是 FK 而非 OneToOne,單一使用者可以依用途分配多把鍵。
- 同時持有 測試環境鍵 與 正式環境鍵
- 開發/運營流程能輕鬆分離
- 日誌與監控也能區分「測試流量」與「真實流量」
7. 認證方式不是優劣,而是「情境武器」
總結我的「情境最佳組合」如下:
- OAuth2:適合外部服務/客戶端整合,需使用者同意的流程
- Session 認證:單一 Django 網站開發速度最快、最簡潔
- JWT:前後端分離、行動端、SPA 等多端平衡最佳
- API Key:後端 ↔ 後端、自動化、Worker、批次等「非使用者請求」情境最為便利
尤其在 Celery Worker 介入時,試圖用「登入基礎認證」統一全局只會增加複雜度。此時 API Key 成為最乾淨的出路。
8. 結語
人(瀏覽器/APP)自然使用 Session/JWT/OAuth2 處理認證。 但 Worker 不是人,而是程式,它必須能「辨識」是哪個客戶的工作。
我轉向 API Key 並非因為安全議題,而是因為在那個環節它是最簡單、最直接的解法。把鍵與使用者綁定後,鍵的管理不再是工具,而是 運營槓桿。
讀者有在使用 API Key 的經驗嗎?本文分享的做法僅是一種便利的示例,期待能為你帶來靈感。
相關文章