在前一篇測試中, 我已將 serverless 第一版原始碼從 GitHub 上複製到本機 Antigravity CLI 的專案目錄下, 並做好前置處理, 包含將原專案打上標籤, 建立新分支, 建立隔離資料夾並移動應用 App, 最後提交 Git 紀錄. 本篇要用 agy 來進行重構, 為 serverless 平台加上 API Token 認證機制.
2. 用 agy 重構專案 :
切換到專案目錄下後輸入 agy 啟動 Antigravity CLI 介面, 這次仍然使用 Claude Sonnet 模型來完成此重構計劃. 輸入下列提示詞 :
我們正在 feature/api-token-auth 分支上,要為這個 serverless 專案加上 API Token 認證機制。請協助修改 serverless.py,完成以下任務:
1. 初始化資料庫:
在系統啟動時(或初始化 DB 的地方),自動建立 `api_tokens` 資料表(欄位包含:id, token, owner, is_active, created_at)。
2. 實作驗證裝飾器(Decorator):
撰寫一個 `@require_api_token` 裝飾器,從請求的 Header 中讀取 `X-API-Key`。
- 若 Header 遺失或 Token 不存在於資料庫中(且 is_active 必須為 1),回傳 401 Unauthorized。
3. 保護 API 路由:
將這個裝飾器套用到「儲存/更新 function」以及「執行 function」的 Flask Route 上。
請先分析原始專案的架構, 提出你的重構計劃, 讓我看過後再修改程式碼。
Claude 閱讀原專案後規劃結果如下 :
> 我們正在 feature/api-token-auth 分支上,要為這個 serverless 專案加上 API Token 認證機制。
請協助修改 serverless.py,完成以下任務:
1. 初始化資料庫:
在系統啟動時(或初始化 DB 的地方),自動建立 `api_tokens` 資料表(欄位包含:id, token, owner,
is_active, created_at)。
2. 實作驗證裝飾器(Decorator):
撰寫一個 `@require_api_token` 裝飾器,從請求的 Header 中讀取 `X-API-Key`。
- 若 Header 遺失或 Token 不存在於資料庫中(且 is_active 必須為 1),回傳 401 Unauthorized。
3. 保護 API 路由:
將這個裝飾器套用到「儲存/更新 function」以及「執行 function」的 Flask Route 上。
請先分析原始專案的架構, 提出你的重構計劃, 讓我看過後再修改程式碼。
▸ Thought for 2s
Let me first explore the project structure to understand the codebase before mak...
● ListDir(D:/antigravity_cli/projects/serverless)
● Read(D:/antigravity_cli/projects/serverless/serverless.py)
● ListDir(D:/antigravity_cli/projects/serverless/functions)
● Read(D:/antigravity_cli/projects/serverless/requirements.txt)
● Read(D:/antigravity_cli/projects/serverless/functions/save_function.py)
● Read(D:/antigravity_cli/projects/serverless/functions/update_function.py) (ctrl+o to expand)
已完整閱讀專案架構,以下是我的分析與重構計劃。
──────
● Create(C:/Users/tony1/.gemini/antigravity-...-a43e-cfa6fbc204e5/refactor_plan.md) (ctrl+o to expand)
以下是重構計劃的摘要:
## 架構分析結論
現有系統有兩層認證:
1. Session Cookie — 管理者透過 /login 密碼登入,保護 PROTECTED_FUNCTIONS 清單
2. 一般函式執行 — 完全沒有保護,任何人只要知道 URL 就能呼叫
──────
## 三個關鍵設計決策
### 1. init_db() 修正
移除 if not os.path.exists(DB_PATH) 判斷,改用 CREATE TABLE IF NOT EXISTS
,確保每次啟動都檢查表是否存在,不會因 DB 已建立但缺表而漏掉建立 api_tokens 。
### 2. @require_api_token 裝飾器
讀取 X-API-Key Header → 查詢 api_tokens 表( is_active=1 )→ 不符合一律回 401 JSON。
### 3. 保護路由的方案
因為 save_function 、 update_function 與一般函式執行共用同一個 handle_function()
路由,無法直接套裝飾器。
採用方案 A:在路由內部邏輯中呼叫驗證輔助函式,改動最小且與現有 Session 機制並存。
──────
計劃文件已整理完畢,請確認後按「Proceed」或告訴我需要調整的地方,即可開始撰寫程式碼。
此計劃看來很周到, 輸入 Proceed 按 Enter 看它表演即可 :
> Proceed
▸ Thought for 1s
The user wants to proceed with the refactoring plan. Let me implement the change...
好的,開始實作!
● Read(D:/antigravity_cli/projects/serverless/serverless.py)
● Edit(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
修改成功,來驗證最終結果:
● Read(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
內容正確。最後修正一個步驟編號的小問題(step 2 重複出現):
● Edit(D:/antigravity_cli/projects/serverless/serverless.py) (ctrl+o to expand)
所有修改完成,以下是完整摘要:
──────
## ✅ 修改完成摘要
檔案:serverless.py
### 變更一覽
# | 位置 | 修改內容
---------------|---------------|------------------------------------------------------------------
1 | L6 | 新增 from functools import wraps
2 | L16–37 | init_db() 改為冪等執行,新增 api_tokens 資料表
3 | L56–73 | 新增 require_api_token(f) 裝飾器(備用,可掛在未來獨立路由上)
4 | L105–106 | 新增 TOKEN_PROTECTED_FUNCTIONS 常數
5 | L167–181 | handle_function() 步驟 2 加入 API Token 驗證邏輯
6 | L207–208 | 移除 __main__ 區塊重複的 init_db() 呼叫
### 認證邏輯流程(修改後)
/function/<func_name>
│
├─ func_name 在 PROTECTED_FUNCTIONS?
│ └─ 未登入 Session → 401 (Authentication required)
│
├─ func_name 在 TOKEN_PROTECTED_FUNCTIONS(save/update)
│ OR func_name 不在 PROTECTED_FUNCTIONS(一般函式)?
│ ├─ 無 X-API-Key Header → 401 (Missing API token)
│ └─ Token 無效或 is_active=0 → 401 (Invalid or inactive API token)
│
└─ 驗證通過 → 動態載入並執行函式
### 快速測試方式
# 插入測試 Token
sqlite3 serverless.db "INSERT INTO api_tokens (token, owner) VALUES ('test-token-123',
'developer');"
# ✅ 正確呼叫
curl http://localhost:5000/function/hello -H "X-API-Key: test-token-123"
# ❌ 無 Token → 401
curl http://localhost:5000/function/hello
不到三分鐘就完成重構了, 這若是照以前人工來改程式碼, 恐怕得花上一周或更久. 我叫 Claude 說明它改了哪些地方 :
> 解釋你修改了哪些檔案? 哪個部分(函式)?
▸ Thought Process
The user wants a clear explanation of which files and which functions were modif...
這次只修改了 1 個檔案,共改動 4 個區塊:
──────
## 修改的檔案
### serverless.py
──────
### 1. Import 區塊(L1–8)
+ from functools import wraps
新增 wraps ,讓裝飾器能保留被包裝函式的原始名稱與文件字串。
──────
### 2. init_db() 函式(L16–37)
改動前:用 if not os.path.exists(DB_PATH) 判斷,只有 DB 不存在時才建表,且只建 call_stats
一張表。
改動後:
• 移除 os.path.exists 條件判斷,改為每次啟動都執行( CREATE TABLE IF NOT EXISTS
本身就是冪等的,不會重複建表)
• 新增 api_tokens 資料表,欄位為 id, token, owner, is_active, created_at
──────
### 3. 新增 require_api_token() 裝飾器(L56–73)
全新函式,位於 record_call() 之後、 app = Flask(...) 之前。
功能:從 Request Header 讀取 X-API-Key ,查詢資料庫確認 Token 存在且 is_active=1 ,否則回傳 401
。
│ 此裝飾器目前定義為備用,供未來掛在獨立路由上使用。
──────
### 4. handle_function() 路由函式(L163–181)
在原有的 Session 驗證之後,插入第二層 API Token 驗證邏輯(步驟 2):
觸發條件(滿足其一即驗證):
A. func_name 在 TOKEN_PROTECTED_FUNCTIONS → save_function、update_function
B. func_name 不在 PROTECTED_FUNCTIONS → 所有一般使用者自訂函式
兩種情況都會檢查 X-API-Key Header,並查詢 api_tokens 表,不符合就回傳 401 。
──────
### 未修改的部分
未動到的檔案/函式 | 原因
-------------------------------------------------|------------------------------------------------
functions/ 目錄下所有模組 | 驗證邏輯集中在 serverless.py ,子模組不需變動
check_auth() | Session 登入機制保持原樣
record_call() | 呼叫統計邏輯不變
/login 、 /logout 路由 | 管理者登入流程不變
這個說明後續可以開啟主程式 serverless.py 來檢視.
3. 功能測試 :
上面 agy 已完成重構, 接下來實地測試 Claud 實作的 API Token 是否能正常運作. 在進行測試之前, 須在專案目錄下建立一個純文字檔 .env, 紀錄管理者的 token 與 key, 前者是自己容易記的密碼, 後者是用工具函式產生的一長串金鑰, 可以用 Python 內建的 secrets 模組來產生, 參考 :
在專案目錄下用記事本編輯一個 .env 檔, 輸入如下內容 (範例) :
SECRET_TOKEN=admin123
SECRET_KEY=fKFQPound41lv8FrWzU-lmFywxAT47uMwfvmBbiuLTE
其中的 SECRET_KEY 可在 Thonny 的 Python 互動環境匯入 secrets 模組後呼叫 secrets.token_urlsafe(32) 函式產生, 例如 :
>>> import secrets
>>> secrets.token_urlsafe(32)
'fKFQPound41lv8FrWzU-lmFywxAT47uMwfvmBbiuLTE'
由於我主要的測試環境主要是使用 Thonny 自帶的 Python, 所有 requirements.txt 中的套件在此開發環境都有安裝 (此專案主要是用到 Flask), 所以按 Thonny 的 "工具/開啟系統終端機" 開啟命令提示字元視窗, 切換到專案目錄下, 用下列指令啟動 Flask 開發伺服器 :
D:\antigravity_cli\projects\serverless>python serverless.py
* Serving Flask app 'serverless'
* Debug mode: on
伺服器運行起來後, serverless.py 就會建立一個 SQlite 資料庫 serverless.db, 執行下列指令在此系統資料庫裡的 api_tokens 資料表填入測試用的權杖 test-token-123 :
PS D:\antigravity_cli\projects\serverless> python -c "import sqlite3; conn = sqlite3.connect('serverless.db'); conn.execute('INSERT INTO api_tokens (token, owner, is_active) VALUES (?, ?, ?)', ('test-token-123', 'developer', 1)); conn.commit(); conn.close(); print('🎉 測試 Token 寫入成功!')"
🎉 測試 Token 寫入成功!
然後在瀏覽器網址列輸入 Flask 開發伺服器預設網址 http://localhost:5000/ 會看到 serverless 平台網站已順利運行, 按 "登入系統" :
輸入 .env 檔案中設定的 SECRET_TOKEN 密碼, 按 "登入" 鈕 :
登入成功後按 "函式列表" 進入管理頁面首頁 :
按 "資料表" :
可見多了一個 api_tokens 的資料表, 這就是 Claude 重構此平台時所添加, 用來儲存 API Key (token) 的資料表, 按 "檢視" :
顯示前面用 Python 指令寫入 api_tokens 資料表的測試用權杖 :
接下來用 curl.exe 測試沒帶 token 的情況, 這樣的請求會被拒絕 :
PS D:\antigravity_cli\projects\serverless> curl.exe -i http://localhost:5000/function/hello
HTTP/1.1 401 UNAUTHORIZED
Server: Werkzeug/2.3.7 Python/3.10.11
Date: Fri, 17 Jul 2026 11:36:12 GMT
Content-Type: application/json
Content-Length: 73
Connection: close
{
"error": "Missing API token",
"hint": "Provide X-API-Key header"
}
可見未攜帶 token 的請求會回應 "401 UNAUTHORIZED". 主體 (body) 內容為 JSON 訊息, error 鍵之值表示沒有收到 API token; 而 hit 鍵之值則表示必須在標頭攜帶 X-API-Key, 可在 curl.exe 指令中用 -H 參數指定此 token, 例如 :
PS D:\antigravity_cli\projects\serverless> curl.exe -i http://localhost:5000/function/hello -H "X-API-Key: test-token-123"
HTTP/1.1 200 OK
Server: Werkzeug/2.3.7 Python/3.10.11
Date: Fri, 17 Jul 2026 15:41:03 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 12
Connection: close
Hello World!
可見若有攜帶正確的 X-API-Key 就會執行該函式, 回應 200 OK.
4. 線上管理 API Key :
在第一版的 serverless 函式執行平台就已實作了線上管理 serverless.db 的功能, 除了提供超連結可刪除資料表與紀錄外, 還可以執行 SQL 指令以新增, 更新, 或刪除紀錄.
按資料表列表頁面下方的 "執行 SQL" :
輸入 SQL 指令後按 "執行" 即可, 例如要修改 owner=developer 使用中的 token 的 SQL 指令 :
UPDATE api_tokens
SET token = 'new-test-token' WHERE owner='developer' AND is_active=1;
執行結果為成功 :
返回資料表內容檢視頁面可知 API Key (token 欄位) 已經更新了 :
新增 API key 的 SQL 例如 :
INSERT INTO api_tokens (token, owner, is_active)
VALUES ('fKFQPound41lv8FrWzU-lmFywxAT47uMwfvmBbiuLTE', 'proj-a', 1);
只要以管理員身分登入, 就可以線上管理 API Key 了.
以上測試顯示 agy 的重構確實達成了預期的目標, 讓 serverless 平台升級為需要 API Key 才能使用的網路服務, 避免伺服器被濫用或遭到攻擊.














沒有留言 :
張貼留言