知識庫 / Spring / Spring Security RSS 訂閱

Spring Security – @PreFilter 和 @PostFilter

Spring Security
HongKong
5
02:43 PM · Dec 06 ,2025

1. 概述

本文將介紹如何使用 <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/access/prepost/PreFilter.html">@PreFilter</a><a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/access/prepost/PostFilter.html">@PostFilter</a> 註解,以在 Spring 應用中實現操作安全。

當與身份驗證主體信息一起使用時,<em>@PreFilter</em><em>@PostFilter</em> 允許我們使用 Spring 表達式語言定義細粒度的安全規則。

2. 介紹

簡單來説, 註解用於根據我們自定義的安全性規則過濾對象列表。

定義了方法返回列表的過濾規則,通過將該規則應用於列表中的每個元素。

如果評估值為 true,則該項目將保留在列表中。否則,該項目將被刪除。

的工作方式非常相似,但是過濾應用於作為方法註解的輸入參數傳遞的列表。

這兩個註解可以應用於方法或類型(類和接口)。在本文中,我們將只在方法中使用它們。

這些註解默認情況下處於禁用狀態——我們需要使用 註解和 (此註解默認啓用) 在我們的安全配置中啓用它們:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig {
    // ...
}

3. 編寫安全規則

為了編寫這些兩個註解中的安全規則,我們將使用 Spring-EL 表達式;我們還可以使用內置對象 filterObject 來獲取正在測試的特定列表元素引用。

Spring Security 提供了許多其他內置對象,可以創建非常具體和精確的規則。

例如,我們可以使用 @PreFilter 來檢查 Task 對象中的 assignee 屬性是否等於當前認證用户的 name

@PostFilter("filterObject.assignee == authentication.name")
List<Task> findAll() {
    ...
}

我們在這裏使用了 @PostFilter 註解,因為我們希望該方法首先執行並獲取所有任務,並將所有任務通過我們的過濾規則。

因此,如果認證用户是 michael,則 findAll 方法返回的任務列表將僅包含分配給 michael 的任務,即使數據庫中存在分配給 jimpam 的任務。

現在,讓我們使規則變得更有趣一些。假設如果用户是經理,他們可以查看所有任務,無論他們被分配給誰:

@PostFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
List<Task> findAll() {
    // ...
}

我們使用內置方法 hasRole 來檢查認證用户是否具有 MANAGER 角色。如果 hasRole 返回 true,任務將被保留在最終列表中。因此,如果用户是經理,該規則將為列表中每個項目返回 true,最終列表將包含所有項目。

現在,我們使用 @PreFilter 過濾一個作為參數傳遞給 save 方法的列表:

@PreFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
Iterable<Task> save(Iterable<Task> entities) {
    // ...
}

安全規則與我們在 @PostFilter 示例中使用的規則相同。主要的區別在於,列表項將在方法執行之前進行過濾,從而允許我們從列表中刪除某些項,防止它們被保存到數據庫中。

因此,非經理 jim 可能會嘗試保存一個任務列表,其中包含一些分配給 pam 的任務。但是,只會包含分配給 jim 的任務,其他的任務將被忽略。

4. 大型列表的性能

@PostFilter 確實很酷且易於使用,但處理非常大的列表時可能會變得低效,因為檢索操作會一次性獲取所有數據並在之後應用過濾。

想象一下,例如,我們數據庫中有數千個任務,並且我們想檢索目前分配給 pam 的五個任務。如果使用 @PostFilter,則 數據庫操作會首先檢索所有任務,然後遍歷所有任務以過濾掉未分配給 pam 的那些任務。

5. 結論

本文快速介紹瞭如何使用 Spring Security 的 @PreFilter@PostFilter 註解創建一種簡單但安全的應用程序。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.