Supabase
核心原則
1. Supabase 變更頻繁 — 在實作前請務必對照更新日誌與當前文件。 請勿依賴訓練資料來處理 Supabase 功能。函式簽名、config.toml 設定以及 API 慣例在不同版本間可能有所差異。
首先,取得 https://supabase.com/changelog.md(一個輕量級的摘要索引 — 非大量下載),掃描與你的任務相關的 breaking-change 標籤,並依據對應連結的頁面來處理。然後使用下列的文件存取方式查詢相關主題。
2. 驗證你的工作。 在實作任何修正後,執行測試查詢以確認變更生效。未經驗證的修正即為不完整的修正。
3. 從錯誤中恢復,而非陷入迴圈。 若某種方法在嘗試 2-3 次後仍失敗,請停下來重新思考。嘗試不同的方法、查閱文件、更仔細地檢查錯誤,並在可行時檢閱相關日誌。Supabase 的問題並非總能透過重複執行相同指令解決,答案也未必總在日誌中,但在繼續之前檢查日誌通常是值得的。
4. 將資料表暴露給資料 API: 根據使用者的 Data API 設定,新建立的資料表可能不會自動透過 Data (REST) API 暴露。若發生此情況,則需要明確授予 anon 和 authenticated 角色存取權限。
請注意,這與 RLS 不同。RLS 控制的是資料表可存取後,哪些「資料列」是可見的,而非資料表本身是否可存取。
當使用者回報透過 SQL 建立的資料表意外無法存取時,請檢查他們的 Data API 設定,以及是否已透過明確的 GRANT SQL 授予角色存取權限。在授予公開(anon/authenticated)存取權限時,請務必同時啟用 RLS。完整的設定流程請參閱將資料表暴露給 Data API。
5. 暴露 Schema 中的 RLS。
在任何暴露的 schema(預設包含 public)中的每個資料表上啟用 RLS。這在 Supabase 中至關重要,因為當 anon/authenticated 角色具有存取權限時(請參閱將資料表暴露給 Data API),暴露 schema 中的資料表可透過 Data API 觸及。對於私有 schema,建議採用 RLS 作為深度防禦。啟用 RLS 後,應建立與實際存取模型相符的策略,而非預設每個資料表都使用相同的 auth.uid() 模式。
6. 安全性檢查清單。 在處理任何涉及 auth、RLS、views、storage 或用戶資料的 Supabase 任務時,請逐一檢查此清單。這些是 Supabase 特有的安全陷阱,會默默地產生漏洞:
-
Auth 與工作階段安全性
- 絕不要在基於 JWT 的授權決策中使用
user_metadata聲明。 在 Supabase 中,raw_user_meta_data是使用者可編輯的,並且可能出現在auth.jwt()中,因此對於 RLS 策略或任何其他授權邏輯來說是不安全的。應將授權資料儲存在raw_app_meta_data/app_metadata中。 - 刪除使用者並不會使現有的存取權杖失效。 請先登出或撤銷工作階段,對於敏感應用程式請保持 JWT 有較短的過期時間,若需要嚴格保證,請在敏感操作中根據
auth.sessions驗證session_id。 - 如果你使用
app_metadata或auth.jwt()進行授權,請記住 JWT 聲明在使用者的權杖刷新之前並不總是最新的。
- 絕不要在基於 JWT 的授權決策中使用
-
API 金鑰與客戶端暴露
- 絕不要在公開客戶端暴露
service_role或密鑰。 前端程式碼請偏好使用公開金鑰。舊版的anon金鑰僅用於相容性。在 Next.js 中,任何NEXT_PUBLIC_環境變數都會被發送到瀏覽器。
- 絕不要在公開客戶端暴露
-
RLS、Views 與特權資料庫程式碼
- Views 預設會繞過 RLS。 在 Postgres 15 及以上版本中,使用
CREATE VIEW ... WITH (security_invoker = true)。在較舊版本的 Postgres 中,請透過撤銷anon和authenticated角色對 view 的存取權限,或將其放置在未暴露的 schema 中來保護你的 view。 - UPDATE 需要 SELECT 政策。 在 Postgres RLS 中,一個 UPDATE 操作需要先 SELECT 該資料列。如果沒有 SELECT 政策,更新會默默地回傳 0 列 — 沒有錯誤,只是沒有變更。
auth.role()已棄用 — 請改用TO子句。 Supabase 已棄用auth.role(),建議直接在政策上使用TO authenticated或TO anon來指定目標角色。除了棄用之外,當啟用匿名登入時,auth.role() = 'authenticated'會默默地失效,因為匿名使用者帶有authenticated這個 Postgres 角色,無論使用者是否真實登入都會通過檢查。-- 已棄用(請勿使用) create policy "example" on table_name for select using ( auth.role() = 'authenticated' );- 僅使用
TO authenticated是認證而非授權(BOLA / IDOR)。 僅使用TO authenticated只會檢查角色 — 它不會限制使用者可以存取哪些資料列。正確的模式是在USING中結合TO authenticated與所有權謂詞:create policy "example" on table_name for select to authenticated using ( (select auth.uid()) = user_id ); - UPDATE 政策需要同時包含
USING和WITH CHECK。 如果沒有WITH CHECK,使用者可以將某個資料列的user_id重新指派給另一個使用者:create policy "example" on table_name for update to authenticated using ( (select auth.uid()) = user_id ) with check ( (select auth.uid()) = user_id ); SECURITY DEFINER函數會繞過 RLS。SECURITY DEFINER函數以其建立者的權限執行 — 通常是具有bypassrls的角色(例如postgres)。絕不要為了解決權限錯誤而新增SECURITY DEFINER;它會在不解決根本原因的情況下默默地移除存取控制。請優先使用SECURITY INVOKER。public中的SECURITY DEFINER函數可被所有角色呼叫。 Postgres 預設會對每個新建的函數授予PUBLIC的EXECUTE權限,因此public中的任何SECURITY DEFINER函數都是一個公開的 API 端點,anon和authenticated(它們繼承自PUBLIC)無需任何額外的授權即可呼叫。當確實需要SECURITY DEFINER時(例如,繞過內部查詢資料表的 RLS),請將函數保留在未暴露的 schema 中,在函數體內務必包含auth.uid()檢查,並在修改後執行supabase db advisors。
- Views 預設會繞過 RLS。 在 Postgres 15 及以上版本中,使用
-
Storage 存取控制
- Storage upsert 需要 INSERT + SELECT + UPDATE 權限。 僅授予 INSERT 權限允許上傳新檔案,但檔案替換(upsert)會默默地失敗。你需要這三者。
對於上述未涵蓋的任何安全性問題,請取得 Supabase 產品安全性索引:https://supabase.com/docs/guides/security/product-security.md
Supabase CLI
始終透過 --help 來探索指令 — 切勿猜測。CLI 結構在不同版本間會有所變更。
supabase --help # 所有頂層指令
supabase <group> --help # 子指令(例如 supabase db --help)
supabase <group> <command> --help # 特定指令的旗標
Supabase CLI 已知注意事項:
supabase db query需要 CLI v2.79.0+ → 替代方案請使用 MCPexecute_sql或psqlsupabase db advisors需要 CLI v2.81.3+ → 替代方案請使用 MCPget_advisors- 當你需要一個新的遷移 SQL 檔案時,務必先使用
supabase migration new <name>建立它。切勿自行編造遷移檔名或憑記憶猜測預期格式。
版本檢查與升級: 執行 supabase --version 來檢查。關於 CLI 更新日誌和版本特定功能,請參閱 CLI 說明文件 或 GitHub releases。
Supabase MCP 伺服器
關於設定說明、伺服器 URL 與組態,請參閱 MCP 設定指南。
連線問題疑難排解 — 請依序執行下列步驟:
-
檢查伺服器是否可達:
curl -so /dev/null -w "%{http_code}" https://mcp.supabase.com/mcp預期會收到401(無權杖),這表示伺服器正在運作。逾時或「連線被拒絕」則表示伺服器可能已關閉。 -
檢查
.mcp.json組態: 確認專案根目錄中存在有效的.mcp.json,且包含正確的伺服器 URL。如果遺失,請建立一個指向https://mcp.supabase.com/mcp的檔案。 -
驗證 MCP 伺服器: 如果伺服器可達且
.mcp.json正確,但工具仍未顯示,則使用者需要進行驗證。Supabase MCP 伺服器使用 OAuth 2.1 — 請告知使用者在其代理中觸發驗證流程,在瀏覽器中完成驗證,然後重新載入工作階段。
Supabase 說明文件
在實作任何 Supabase 功能之前,請先找到相關說明文件。請依優先順序使用以下方法:
- MCP
search_docs工具(首選 — 直接回傳相關片段) - 以 Markdown 格式取得說明文件頁面 — 任何文件頁面都可以透過在 URL 路徑後附加
.md來取得。 - 網路搜尋 Supabase 特定主題,當你不知道該查看哪個頁面時。
建立與提交綱要變更
若要進行綱要變更,請使用 execute_sql(MCP)或 supabase db query(CLI)。 這些方法會直接在資料庫上執行 SQL,而不會建立遷移歷史記錄條目,因此你可以自由迭代,並在準備好時產生乾淨的遷移。
請勿使用 apply_migration 來變更本地資料庫綱要 — 它會在每次呼叫時寫入一個遷移歷史記錄條目,這意味著你無法迭代,而且 supabase db diff / supabase db pull 會產生空的或衝突的差異。如果你使用了它,你將會被困在你第一次嘗試時傳入的任何 SQL 上。
當準備好提交變更到遷移檔案時:
- 執行 advisors →
supabase db advisors(CLI v2.81.3+)或 MCPget_advisors。修正任何問題。 - 審閱上述的安全性檢查清單,如果你的變更涉及 views、functions、triggers 或 storage。
- 產生遷移 →
supabase db pull <descriptive-name> --local --yes - 驗證 →
supabase migration list --local
參考指南
- 技能回饋 → references/skill-feedback.md 當使用者回報此技能提供了錯誤的指導或遺漏資訊時,務必閱讀