在昨天(Day 25)我們認識了 RBAC(基於角色的存取控制),它透過角色分配權限,適合大部分企業場景。
但當系統需求變得更複雜,單純依靠角色有時會顯得僵化。這時候就需要更進一步的模型:ABAC(Attribute-Based Access Control,基於屬性的存取控制)。
ABAC 的核心:
透過 屬性(Attribute) 來決定使用者是否能存取資源。
屬性可以來自不同面向:
判斷邏輯:
系統會檢查一組「策略(Policy)」來決定是否授權,例如:
「財務部門的員工只能在上班時間(9:00-18:00)查詢報表。」
特性 | RBAC(角色導向) | ABAC(屬性導向) |
---|---|---|
授權依據 | 使用者所屬角色 | 使用者、資源、環境等屬性 |
適合場景 | 固定職責、層級清晰的組織 | 複雜條件、跨角色、需要動態策略的系統 |
彈性 | 中等(新增角色即可調整) | 高(幾乎無限可能,但需策略管理) |
實作難度 | 較低 | 較高(需策略引擎與條件判斷) |
換句話說:
Spring Security 本身雖然沒有完整的「策略引擎」,但可以透過以下方式模擬 ABAC:
方法層級註解
使用 @PreAuthorize
與 SpEL(Spring Expression Language)檢查屬性。
範例:
@PreAuthorize("#document.owner == authentication.name")
public Document getDocument(Document document) { ... }
自訂 AccessDecisionVoter
結合外部 Policy Engine
在 RBAC/ABAC 的語境下,「資源授權」特別指 針對特定資源實體的存取控制,而不是單純 URL。
例子:
/orders/123
→ 只有建立這筆訂單的使用者能修改。/files/abc.pdf
→ 只有擁有者或管理員能刪除。Spring Security 的做法:
透過 方法層級檢查
@PreAuthorize("#order.customerId == authentication.principal.id")
public void updateOrder(Order order) { ... }
或者 Service 層判斷
if (!order.getCustomerId().equals(auth.getName())) {
throw new AccessDeniedException("Not your order!");
}
這樣就能實現「物件級授權」,避免敏感資料被越權存取。
ROLE_DOCTOR
→ 查看病歷ROLE_NURSE
→ 查看病歷ROLE_PATIENT
→ 查看病歷@PreAuthorize("#record.ownerId == authentication.principal.id")
@PreAuthorize("#record.department == authentication.principal.department")
ABAC 與資源授權讓授權控制更貼近真實商業邏輯:
在下一篇(Day 27),我們將示範 Spring Security 中的方法層級授權(@PreAuthorize、@PostAuthorize) 的實際應用,讓理論走向實作。
今天就分享到這裡,我們明天見!