API 驗證與安全
以 Session、CSRF、租戶權限及請求去重保護每次操作。
連線與驗證
目前提供同來源工作台 API,尚未提供個人 API Token 或公開服務端 API Key。請先登入,並使用瀏覽器管理的 Session Cookie。
http
GET /api/v1/auth/csrf HTTP/1.1
Accept: application/jsonjson
{
"token": "<csrf-token>"
}修改請求需帶 X-CSRF-TOKEN 及 Idempotency-Key。登入、登出後重新取得 token;不要把 Cookie、密碼或 token 寫入日誌。
快速開始
javascript
// 在同一站點的瀏覽器環境執行;沿用 Session Cookie。
const base = '/api/v1';
const csrf = async () => {
const res = await fetch(base + '/auth/csrf', {
credentials: 'same-origin', headers: { Accept: 'application/json' }
});
if (!res.ok) throw new Error('無法取得 CSRF');
return (await res.json()).token;
};
let token = await csrf();
const login = await fetch(base + '/customer/auth/login', {
method: 'POST', credentials: 'same-origin',
headers: {
Accept: 'application/json', 'Content-Type': 'application/json',
'X-CSRF-TOKEN': token, 'Idempotency-Key': crypto.randomUUID()
},
body: JSON.stringify({ login: '[email protected]', password: '<password>' })
});
if (!login.ok) throw new Error('登入失敗');
token = await csrf(); // 登入會更新 Session,重新取得 token。
const res = await fetch(base + '/customer/posts?page=1&per_page=10', {
credentials: 'same-origin', headers: { Accept: 'application/json' }
});
if (!res.ok) throw new Error('查詢失敗');
const data = await res.json();修改資料、版本與重試
每個新操作產生一個 UUID,同一操作的重試沿用相同 UUID 與相同內容。revision 使用讀取文章或排程時回傳的最新值;成功後採用回應的新 revision。
http
PATCH /api/v1/customer/posts/81 HTTP/1.1
Content-Type: application/json
Accept: application/json
X-CSRF-TOKEN: <csrf-token>
Idempotency-Key: 9c5a7a92-a62a-4ff9-921f-5806be34797f
Cookie: <session-cookie>json
{
"revision": 2,
"title": "文章標題",
"excerpt": "文章摘要",
"content": "<h2>第一段</h2><p>文章內容。</p>"
}API 根路徑為 /api/v1。多租戶帳戶可帶 X-Workspace-ID 指定租戶;它是帳戶租戶 ID,與發布工作空間 workspace_id 不同。伺服器仍會驗證 membership,不能藉此存取其他租戶資料。
上傳圖片
使用 FormData,讓瀏覽器自動加入 multipart boundary;不要手動填入 JSON Content-Type。
javascript
const body = new FormData();
body.append('file', fileInput.files[0]);
body.append('revision', String(post.revision));
const response = await fetch('/api/v1/customer/posts/' + post.id + '/images', {
method: 'POST', credentials: 'same-origin',
headers: { Accept: 'application/json', 'X-CSRF-TOKEN': token,
'Idempotency-Key': crypto.randomUUID() },
body
});HTTP 狀態與錯誤
| 狀態碼 | 含義 | 處理方式 |
|---|---|---|
| 401 | 登入狀態失效 | 重新登入。 |
| 403 | 權限不足 | 確認帳戶與租戶權限。 |
| 404 | 資料不存在或不可存取 | 確認資料 ID 屬於目前租戶。 |
| 409 | 版本衝突或操作衝突 | 重新讀取資料;檢查是否已有執行中的任務。 |
| 419 | CSRF/Session 已更新 | 重新取得 CSRF token 再操作。 |
| 422 | 欄位驗證或業務條件不符合 | 閱讀 message 與 errors,修正參數。 |
| 429 | 請求過於頻繁 | 依 Retry-After 等候後重試。 |
| 500 / 502 / 503 | 服務或上游異常 | 先查生成/發布狀態;同一操作沿用 UUID。 |
json · 422 example
{
"message": "The title field is required.",
"errors": {
"title": [
"The title field is required."
]
}
}欄位驗證失敗可能包含 errors;其他錯誤以 HTTP 狀態碼與 message 為準。