Spring Security – @PreFilter 和 @PostFilter

Spring Security
Remote
0
10:21 PM · Nov 29 ,2025

1. 概述

在本文中,我們將學習如何使用 @PreFilter@PostFilter 註解來在 Spring 應用程序中安全操作。

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

2. 介紹

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

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

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

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

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

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

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

3. 編寫安全規則

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

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

例如,我們可以使用 @PreFilter來檢查 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.