Skip to Content
核心概念權限與 ACLACL 總覽

自訂資料表 ACL

ACL 決定 principal 能否存取一張表,以及可讀、可新增、可編輯哪些 rows 和 columns。前端可以用權限摘要調整控制項,但真正的授權永遠在伺服器端:隱藏按鈕不等於阻止 API 呼叫。

四層判斷

端點所需 privilege → effective grant(manager / user / department / chatroom / default) → row access(none / own / filtered / all) → column visibility(column_acl + visible_columns) → 若有 SCP,再套 acting-room / invariant floor

Grant 的解析不是把所有來源任意聯集。一般情況先命中的 grant 勝出;chatroom share 對原本就在 table scope 內的使用者有特別的「只能放寬 baseline」規則。完整步驟見 effective permissions

Grant matrix

來源Chatroom tableDepartment tableCompany table管理端點與用途
User grantpermissions.grant,指定 user
Department grantdepartmentPermissions 只適用 chatroom table;另一組 departmentTableGrants 可把 department 或 company table 分享給一個 department,受贈方路徑段名為 {target_department_id}
Chatroom grantDepartment table 分享給 room;每個 internal / external audience 各自一列,可帶 SCP scope_values
Client / CRM grantclientPermissions 在三種 table scope 都能指定 social-media client 的 external access
Client permission requestClient 可申請存取——包含分享進其聊天室的部門表;由審核者(明確 moderator、部門或公司 manager)approve / reject,approve 會產生 explicit client grant
Passphrase accessclientAccess 在三種 table scope 都可設定共用 passphrase 與套用的 client permissions
Explicit table moderatorscope manager 已隱含Department / company table 可增刪 moderator;manager 一律 full implicit access。指派錨定在該表的 effective company,因此 moderator 不必屬於擁有它的部門
Table defaults只對 in-scope internal users做 fallback——唯一例外是帶著 default_permissions.audience: "company" 的部門表,它讓同公司的每個人都算 in-scope 並為他們開門

完整端點清單見 grant 類型。Table-level column hide map 另由 columnAcl.update 管理。

在 department-scoped table 上,grant 只回答了一半:by-id 路由前面那道 membership door 有自己的一份鑰匙清單,而它以前比 resolver 的短。見部門表的門由誰打開

找到別人分享給你的表

每一條 table LIST 路由都帶 scope 前綴,而被授權的人通常不知道是哪個部門或哪個房間分享給他。兩條沒有 scope 的路由補上這個缺口,而且刻意互補:

  • tables.sharedWithMe 列出從你的 scope 之外送到你手上的東西——per-user grant、你所屬部門的 grant、透過你所屬活房間的 internal chatroom grant,或分享給全部部門的部門表——並附上放行的 sources 與你解析後的權限。你自己部門的表、company scope 的表、你所屬房間的表都被刻意排除。
  • tables.resolveByName 把精確表名轉成 id,範圍涵蓋 company department scope,逐表由 resolver 把關,而不是用角色把關。

兩者都不是你 scope 清單的超集,而且有一個缺口兩者都補不上:角色低於 CAN_MANAGE_COMPANY 的呼叫者若在 company scope 表上握有 per-user grant,那張表不會出現在任何清單上——company 清單是角色門檻,而 discovery 無條件排除 company scope。那一張只能用名稱解析。

上表中每一種 row policy 介面都用同一棵布林樹——and / or / not 包住 predicate 與 link_target leaf——並接受每次請求解析的 tokens——$me$me.department$today$today±Nd$now——以原字串儲存,並在伺服器解析當下 principal 時代換。在 principal 欄位上,兩個身分 token 解析成 tagged user: / smc: / room: cell 的 SET,而不是單一 scalar id;在 agent session 裡,acting room 縮小該 SET 的 room 腿的方式,與它縮小 chatroom grant 那一步完全相同——見 effective permissions。這些介面都不在任何 feature flag 之後:row policies、column ACL、visible_columns、chatroom share grants 與 SCP floors 一律啟用,這裡的端點也不會再回「requires CUSTOM_TABLE_…」之類的錯誤。

權限等級詞彙

名稱意義
Joined已加入該 chatroom;不必先取得 table grant
Tenant已通過該 department/company 的 tenant 身分邊界;不等於 moderator
Access已通過這張表的 effective access dependency
ModeratorTable creator、適用的 scope manager,或 explicit table moderator;可管理表設定與 grants

不同 endpoint family 的 dependency 並不完全一致。不要從某一個成功呼叫推論其他端點也可用。

踢人與離開現在真的關得上門。 POST /private/chatrooms/kick/{chatroom_id}POST /private/chatrooms/leave/{chatroom_id} 過去回 200,卻沒有把成員關係本身寫進去:暫存的移除在同一個請求裡被後續的鎖定重讀覆蓋掉,user_chatroom_association 那一列因此存活,被踢的人在該房間的自訂資料表路由上照樣拿 200。正式環境曾經連踢四次,成員還是列在那裡。現在這些暫存的移除會在那些重讀之前先 flush,所以 200 之後,成員關係與 collector/manager/social media manager 三種角色列在新的 session 上也確實消失,前成員的存取會翻成:table-id 資料列路由回 403 {"detail":"Not a member of this chatroom."}GET .../chatroom/{chatroom_id}/tables403 {"detail":"Insufficient permissions, not a member (Required department manager)."}(或公司管理者版本的字串)。他的 explicit grant 列與 moderator 列一直都刪得掉——那些是 raw delete——所以這個修正針對的正是成員關係本身。若前成員握有 member-independent grant,或本身就過得了 CAN_MANAGE_DEPARTMENT / CAN_MANAGE_COMPANY 的角色 fallback,存取權仍然成立。

Chatroom scope 決策表

操作 family最低 privilege為什麼
新增欄位ModeratorSchema mutation 只交給 table manager
Lifecycle diagnosisModeratorChatroom 診斷可能揭露修復資訊
Resolve linksJoined只需 room membership;目標資料仍由 endpoint 內部可見性限制

Department scope 決策表

操作 family最低 privilege與其他 scope 的差異
新增欄位Access這裡不是 Moderator;已取得 table access 即可
Lifecycle diagnosisModerator這裡比 company 嚴格
Resolve linksTenant不要求先有這張表的 Access dependency

Company scope 決策表

操作 family最低 privilege與其他 scope 的差異
新增欄位Moderator與 chatroom 相同,與 department 不同
Lifecycle diagnosisAccess與 chatroom / department 的 Moderator 不同
Resolve linksAny authenticated user只驗證登入;資料解析仍不應被當成額外授權

這三個 family 的精確 endpoints 是 columns.createlifecycle.diagnosisrecords.linksResolve。前端 route guard 應按「scope + endpoint」建表,不要只做一個全域 isModerator 判斷。

安全的前端策略

  1. 進入表格時呼叫 permissions.me,取得公開的四欄摘要。
  2. 依實際 endpoint privilege 顯示控制項;任何 403 都視為伺服器的最新決定。
  3. 不在 client 重算 row filter 或 hidden columns;只呈現伺服器回傳的 rows / fields。
  4. Grant 變更或 revoke 後重新抓取摘要與資料。Revoke 只是移除一個來源、讓使用者落到下一層;revoke 的回應會回報結果權限,並在這次移除放寬了使用者的存取範圍時標示出來。

Row filters 見 grants,每次請求的 $me / $today 詞彙與空值 cell 規則見 row policy tokens,兩種欄位機制見 column visibility,SCP floor 見 SCP 與 ACL

Last updated on