RBAC 權限怎麼運作

這篇寫給第一次接觸慈恩園系統權限的人。
完整規格以 GitHub issue #246 為準;本頁已在 2026-06-30 對照當時的程式碼與測試。

先記住一句話

系統不是在程式裡寫死「會計可以做什麼、出納不能做什麼」,而是:

使用者打開某個網址或呼叫 API
→ 系統判斷這是哪一項功能
→ 系統判斷這次要查看、新增、修改、刪除還是匯出
→ 檢查使用者登入時拿到的權限
→ 決定放行或拒絕

例如:

會計按下「開立發票」
→ 系統認出這是 AccountingReview(會計審核)
→ 這次操作屬於 U(修改)
→ 使用者有 AccountingReview:U
→ 放行

這就是 issue #246 所說的:

route → feature → grant
網址/API → 功能權限 → 角色被授予的權限

新人最常問的問題

為什麼畫面上沒有某個按鈕?

前端會先檢查權限,沒有權限就隱藏按鈕。

常見寫法:

const { canCreate, canUpdate } = usePermission('Customer')

但是「隱藏按鈕」只是讓畫面比較合理,不是安全防線。有人仍可能直接呼叫 API,所以後端還會再檢查一次。

為什麼看得到按鈕,按下去卻出現 403?

通常表示前端和後端檢查的權限不同。

例如前端用 CertificatePurchase:U 顯示「開立發票」,但後端真正要求的是 AccountingReview:U。前端覺得可以按,後端卻拒絕,便會出現 403。

遇到這種問題,不要只改前端或只放寬後端;要先找出這個動作真正屬於哪個功能。

為什麼管理員改完角色權限,使用者還是不能操作?

權限會放進使用者登入時取得的 JWT。管理員改完角色授權後,該使用者必須 重新登入,才會拿到新的權限。

SystemAdmin 也需要逐項勾權限嗎?

不需要。SystemAdmin 在前端與後端都會直接放行。

這是特例;其他角色仍以實際授權為準。

權限字母代表什麼?

系統使用六個字母表示操作類型:

字母白話說明例子
M可以從選單進入看得到「客戶管理」選單
V可以查看查詢客戶、查看申請單
C可以新增新增客戶、建立申請
U可以修改編輯資料、審核、完成
D可以刪除刪除或作廢資料
E可以匯出匯出 Excel/報表

登入後的權限大致長這樣:

Customer:C,V
Application:M,V,U
AccountingReview:U

意思是:

  • 可以查看、新增客戶。
  • 可以從選單進入申請單,並查看、修改申請單。
  • 可以執行會計審核動作。

系統目前會自動把 M 一併視為 V:既然能進入功能頁,至少也要能讀取頁面資料。

後端實際怎麼判斷?

所有一般 API 都會經過 ApiPermissionFilter

它依序處理:

  1. 這支 API 是否允許匿名使用?
  2. 使用者是否已登入?
  3. 帳號是否被停用,登入憑證是否已失效?
  4. 這支 API 是否只要求「有登入即可」?
  5. 使用者是否為 SystemAdmin
  6. 這次操作需要哪一個功能與操作權限?
  7. 使用者是否真的有該權限?

API 權限有三種判斷方式

1. API 自己明確寫出權限

重要或特殊功能會直接標示:

[FeatureAccess("CustomerSensitive", "U")]

意思是:這支 API 要求「修改客戶敏感資料」權限。

這種方式最清楚,常用在客戶敏感欄位、印鑑卡、會計審核等特殊動作。

2. 共用 API 按網址自動判斷

系統很多功能共用 Query、Post、Put、Delete controller。

例如:

/Query/Customer → Customer:V
/Post/Customer  → Customer:C
/Put/Customer   → Customer:U

少數動作不能只看功能名稱。例如權狀申購的「開立發票」雖然掛在 CertificatePurchase 網址下,實際上屬於會計工作,所以後端會改判成 AccountingReview:U

3. 舊的專用 API 還沒有標權限

如果一支專用 controller 沒有寫 [FeatureAccess],也不是共用 API, 目前會暫時採「登入即可」。

後端同時會記錄:

[RBAC-DEDICATED-TODO]

這是過渡機制,不是新 API 可以照抄的標準。

為什麼同一個功能還要拆出特殊權限?

因為「可以使用申請單」不代表「可以做會計審核」。

如果所有動作都只檢查 Application:U,行政、出納、會計可能互相做到不屬於 自己的工作。系統因此把敏感動作拆成更精確的功能權限:

權限可以做什麼主要授權對象
AccountingReview:U會計審核、處理發票會計
CashierReview:U確認收款、出納退回出納
ApplicationOverride:U完成、確認附件、操作他人建立的申請單管理處/主管
CustomerSensitive:U修改客戶姓名、身分證字號管理處/主管
SealCard:V,C,U查看、上傳、作廢印鑑卡管理處/主管

這種「不同職務不能互相代做」的設計叫 SoD(職責分離)。

新人不需要先背 SoD;只要記得:

敏感動作應該有自己的功能權限,不能只借用所在頁面的通用修改權。

角色授權畫面和左側選單不是同一件事

有些權限只控制按鈕或特殊動作,不需要出現在左側選單。例如 AccountingReviewCustomerSensitive

因此系統分成兩條資料:

  • 角色授權畫面:列出所有可授權的功能,包括不顯示在選單的特殊權限。
  • 使用者左側選單:只顯示設定為可見,而且使用者具有 M 權限的項目。

所以「不在左側選單出現」不代表「管理員不能授權」。

管理員可以在「受控動作權限(SoD)」群組中調整五項特殊權限。

有些限制不是按鈕權限

有些規則要看「這一筆資料屬於誰」,不能只看功能權限。

例如申請單:

  • 建立者可以操作自己建立的申請單。
  • 其他人必須另外具有 ApplicationOverride 才能操作。

這類規則放在 service 裡判斷,稱為資料範圍或列級限制。

目前後台具有 Reservation 權限的角色可以查看全部訂位。未來若要做 「經銷商只能看自己的訂位」,也應在 service 依可靠的使用者/經銷商 ID 限制,不能拿顯示姓名來比對。

目前已知的問題

以下不是理論上的風險,而是 2026-06-30 對照程式碼後仍存在的情況。

1. 權狀申購的發票按鈕可能看得到但不能按成功

畫面目前用 CertificatePurchase:U 決定是否顯示會計操作面板,後端卻要求 AccountingReview:U

可能症狀:

  • 行政人員看得到發票按鈕。
  • 按下後 API 回傳 403。

正確方向:前端也應使用 AccountingReview:U

2. 沒有新增客戶權限的人仍可能進入新增頁

權狀申購、選位等頁面共用的客戶搜尋區塊會顯示「建立新客戶」,但目前沒有先 檢查 Customer:C

可能症狀:

  • 使用者可以進入新增客戶頁。
  • 填完資料後,儲存時才被後端拒絕。

是否要授予會計/出納新增客戶權限仍需 PM 或管理員決定;不論決定為何, 前端按鈕都應與 Customer:C 對齊。

3. 部分電子簽核查詢目前只要登入就能呼叫

SignatureController 的建立動作已要求 Signature:C,但下列動作尚未標示 權限:

  • 取得目前簽核
  • 查看簽核歷程
  • 驗證簽核鏈

它們目前會走前面提到的「舊 API 過渡放行」。

4. 舊版行動 App API 仍允許匿名

ZionApiController 整個 controller 仍標示 [AllowAnonymous]

這是已知的舊系統安全債,不是一般 API 的開發範例。

5. 有一段註解已經過期

auth-store.ts 還寫著「敏感欄位/印鑑卡折回 Customer:U」,但實際程式已改用:

  • CustomerSensitive
  • SealCard

調查問題時應以實際 controller、前端元件與權限 contract 為準,不要只相信 這段舊註解。

修改權限時要檢查哪些地方?

如果新增功能或修改權限名稱,至少確認:

  1. 後端 API 最後判斷的是哪個功能與操作字母。
  2. 前端按鈕是否檢查同一個權限。
  3. 頁面路由守衛是否使用正確功能名稱。
  4. rbac-features.json 是否登錄該功能。
  5. migration 是否建立 tb_menu 功能與角色授權。
  6. 修改角色權限後,是否重新登入再測試。
  7. 是否分別使用有權限、沒有權限的角色實際操作。

不要只用 SystemAdmin 測試,因為 SystemAdmin 會跳過所有權限檢查。

給需要追程式的人

想查什麼從哪裡開始
後端為什麼放行或回 403api/Filters/ApiPermissionFilter.cs
網址如何轉成功能權限api/Filters/FeaturePermission.cs
特殊 API 明確要求什麼權限搜尋 [FeatureAccess(...)]
前端按鈕怎麼判斷composables/usePermission.tsauth-store.ts
頁面進入權限middleware/auth.global.ts
角色授權樹MenuService.GetAllMenusAsyncEditRoleModal.vue
左側選單MenuService.GetUserMenuAsync
系統有哪些正式功能權限contracts/rbac-features.json
DB 種子migrations 301–306

這篇內容怎麼驗證的?

2026-06-30 的檢查結果:

  • issue #246 的核心設計已存在於 develop
  • SoD 主要程式與 migrations 303–306 已存在。
  • RBAC 相關目標測試:29 個通過、0 個失敗。
  • 本次沒有重新查詢 grace2,因此不把 issue 在 2026-06-27 記錄的 DB 驗證 當成本次即時結果。
  • ActionFeatureOverrides 目前沒有直接單元測試,這部分是以程式碼對照確認。

名詞小抄

名詞白話說明
RBAC依角色分配功能權限
feature一項可以被授權的功能,例如 Customer、AccountingReview
operation/op查看、新增、修改、刪除等操作字母
grant管理員把某項權限授給角色
JWT/claim使用者登入後隨身攜帶的權限資料
route使用者進入的網址或呼叫的 API 路徑
SoD職責分離,避免不同職務互相代做敏感工作
403已登入,但沒有執行這項操作的權限