驗證與角色
只收 JWT — 刻意的設計
這個 router 刻意掛載在 TeamSync 一般 private router 之外,因為一般通道同時也接受整合用的 x-api-key 憑證。Edge Workers 只接受 Authorization: Bearer <TeamSync JWT>:
- 沒帶 token,或 token 無法解碼為 TeamSync JWT → 418
Could not validate credentials(附WWW-Authenticate: Bearer)。 - 非 JWT 憑證(
x-api-key整合金鑰、restricted key)根本不會被讀取,所以沒有有效的 Bearer JWT 時,得到的是同一個 418。模組另外保留一道防禦性的 403Edge Workers require TeamSync JWT authentication檢查,但已發佈的只收 JWT 依賴不會走到它。 - JWT 缺少
sub/company_idclaims → 404Could not validate credentials (username) not found;JWT 對應的使用者不存在 → 404User not found。 - JWT 有效、但帳號未通過共用的帳號檢查 → 451
Account expired、401Account not verified yet、409Account disabled或 410Account deleted(依此順序檢查)。
租戶錨定
JWT 只用來識別使用者。租戶身分來自解析後的資料庫使用者列 — user.company_id + user.department_id — 絕不來自 claims 或請求欄位,所以用戶端永遠無法選擇別人的租戶。每個部門層級的路由都會重新讀取這一列,並要求它仍然有效(未刪除、未停用、已驗證、未過期);否則回 403 A live Edge Worker user is required(上面的帳號檢查會先回應,所以這個 403 只會出現在兩次讀取之間帳號狀態改變時)。principal 另外要求部門必須存在、屬於該公司、且未被軟刪除;部門缺失/已刪除/異公司一律是統一的 403 A live department identity is required for Edge Workers(使用者身上過期的 department_id 是 403,與「我的部門還沒有 Worker」的 404 刻意區分)。
之後每個查詢都同時以 company_id 和 department_id 過濾;異租戶與不存在的資源回傳相同的 404(Department Worker not found)。
三層關卡
| 關卡 | 條件 | 使用範圍 |
|---|---|---|
| 成員 | 任何持有效 JWT、不是服務帳號、且有一個存活所屬部門的使用者 — 沒有角色門檻 | GET /worker、版本讀取、部署輪詢、openapi.json、invoke、starter(/starters/**,見範本與原始碼) |
| 部門管理者 | 角色 ≥ CAN_MANAGE_DEPARTMENT(環境變數,預設 2) | 提交、部署、存取政策(含讀取)、Worker 層級 API 金鑰、操作設定與操作 API 金鑰(含讀取)、Worker 機密(含清單)、執行期設定(含讀取)、版本原始碼下載、服務帳號路由(/service-accounts*) |
| 公司管理者 | 角色 ≥ CAN_MANAGE_COMPANY(環境變數,預設 3) | /company/departments* 清單總覽 + 修復,以及服務帳號的對應路由 /company/departments/{department_id}/service-accounts* |
角色不足 → 403 Insufficient permissions.
部門層級路由的其他拒絕,一律是 403:
Service accounts cannot invoke Edge Workers— 呼叫者是部門服務帳號(見下)。A live Edge Worker user is required— 重新讀取的使用者列不存在、已刪除、已停用、未驗證或已過期。A department identity is required for Edge Workers— 該使用者沒有部門。A live department identity is required for Edge Workers— 部門缺失、已軟刪除或屬於別的公司。
公司路由的目標部門來自路徑,但被圍在管理者自己的公司內(存活、未刪除)— 否則 404 Department not found。服務帳號的對應路由也一樣。用戶端提供的 department_id 永遠無法擴大租戶範圍。
服務帳號
部門服務帳號是 Worker 的對外身分:由平台擁有的使用者,handler 以它的身分登入(context.teamsync.authHeaders())去呼叫其他 TeamSync API。它絕不是呼叫 Edge Workers 的方式,每一條 Edge Workers 路由都會拒絕它。成員路由(GET /worker、版本讀取、openapi.json、invoke、/starters/**)回 403 Service accounts cannot invoke Edge Workers。管理者與公司路由先被角色門檻擋下 — 服務帳號的角色是 0,所以看到的是 403 Insufficient permissions. — 而在部門路由上,同一個明確的拒絕仍排在這道門檻之後。建立、重設與刪除服務帳號是一般的管理者操作,由人類的 JWT 使用者執行。見服務帳號。
請求
Authorization: Bearer <jwt>憑證故事就這麼多:沒有 cookie、沒有 x-api-key、沒有簽名 URL。注意:有大小上限的路由(版本上傳、存取政策與其金鑰、執行期設定、機密寫入、操作設定、公司修復)的 413 大小檢查在驗證之前執行(匿名的超大 body 會拿到 413 而不是 418);服務帳號路由沒有路由層級的 body 上限。後端生成的 OpenAPI 中,這些路由只宣告一種安全機制(OAuth2PasswordBearer)。
公開 dispatcher 通道是另一回事 — 它的憑證(如果有的話)是 X-TeamSync-Worker-Key 標頭裡的 Worker API 金鑰(Worker 層級金鑰,或有設定時該操作自己的金鑰),由該操作適用的存取模式決定(逐操作存取),與 TeamSync JWT 無關。