知識庫 / Spring / Spring Security RSS 訂閱

Spring Security 表達式入門

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

1. 引言

在本教程中,我們將重點介紹 Spring Security 表達式及其在實踐中的應用。 Spring Security 表達式提供了一種聲明式定義授權規則的方式。

它們允許在指定誰可以訪問特定 URL 或執行某些方法時具有靈活性。 這些表達式對於在我們的應用程序的各個級別處理安全至關重要,從 Web 請求授權到方法級別安全。

在查看更復雜的實現,例如 ACL,之前,重要的是要對安全表達式有紮實的理解,因為它們在正確使用時可以非常靈活和強大。

2. Maven 依賴

為了在我們的項目中使用 Spring Security,我們在 pom.xml 中包含了以下依賴:

<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>6.1.5</version>
   </dependency>
</dependencies>

<p><em>spring-security-web</em> 依賴項是 Spring Security 的關鍵組成部分,而 spring-core 和 spring-context 則對於構建一個功能完整的 Web 應用程序是必需的。</p>

3. 配置

Spring Security 可以通過基於 Java 的配置進行配置,這提供了更好的靈活性,並且是大多數現代 Spring 應用中推薦的方法。 下面是一個示例:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("com.baeldung.security")
public class SecurityJavaConfig {
    ...
}

@EnableGlobalMethodSecurity 註解允許使用@PreAuthorize@PostAuthorize 註解,從而實現方法級別的安全控制。通過這些註解,我們可以應用在方法執行之前或之後的安全邏輯。

4. Web 安全表達式

讓我們深入瞭解一些常見的 Spring Security 表達式:

4.1. hasRole(), hasAnyRole()

這些表達式用於指定訪問特定 URL 或方法的所需角色:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
      .antMatchers("/auth/admin/*").hasRole("ADMIN")
      .antMatchers("/auth/*").hasAnyRole("ADMIN", "USER")
      .build();
}

上述示例確保只有擁有ADMIN角色的用户才能訪問以/auth/admin/開頭的URL,而ADMIN角色和USER角色均可訪問以/auth/開頭的URL。

4.2. hasAuthority(), hasAnyAuthority()</h3

Roles 和 authorities 都是用於訪問控制的,但它們語義略有不同。 Authorities 不需要 ROLE_ 前綴,Spring 會自動為其添加該前綴。 建議使用 authorities 代替 roles,因為它提供了更大的靈活性。

以下是一個定義具有特定 authorities 的用户的快速示例:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/auth/admin/*").hasAuthority("ADMIN")
        .requestMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER"
      )
      .build();
}

4.3. permitAll(), denyAll()

這些表達式允許我們明確地允許或拒絕訪問特定的 URL。 讓我們來看一個例子:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/public/**").permitAll()
        .requestMatchers("/private/**").denyAll()
      )
      .build();
}

此配置使用 permitAll() 允許任何人訪問以 /public/ 開頭的 URL,從而使它們公開可用,而 denyAll() 則完全阻止對以 /private/ 開頭 URL 的訪問,從而有效地禁用這些資源。

4.4.isAnonymous()、isRememberMe()、isAuthenticated()、isFullyAuthenticated()

這些表達式控制基於用户身份驗證狀態的訪問權限:

  • isAnonymous():允許未身份驗證的用户訪問。
  • isAuthenticated():限制對已身份驗證的用户訪問。
  • isFullyAuthenticated():要求用户在執行敏感操作時重新身份驗證。
  • isRememberMe():允許通過“記住我”功能身份驗證的用户訪問。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/login").anonymous()
        .requestMatchers("/dashboard").authenticated()
        .requestMatchers("/settings").fullyAuthenticated()
      )
      .build();
}

在本示例中,我們使用 anonymous() 以確保僅未身份驗證的用户可以訪問 /loginauthenticated() 要求用户已登錄才能訪問 /dashboard,而 fullyAuthenticated() 則強制要求對敏感的 /settings 訪問進行全新登錄,從而增強安全性。

4.5. 主要身份驗證 (principal, authentication)

Spring Security 通過 PrincipalAuthentication 對象提供當前用户身份驗證的詳細信息。這些對象包含有關已認證用户的信息,例如用户名和角色。

例如,當用户向受保護的端點發出請求時,我們可以使用 Principal 對象檢索其詳細信息:

@GetMapping("/profile")
public String profile(Principal principal) {
    return "Hello, " + principal.getName();
}

在本示例中,profile() 方法從 Principal 對象中提取已登錄用户的姓名,並返回一個問候消息。

或者,如果我們需要關於身份驗證的更多信息,例如角色或身份驗證類型,我們可以使用 Authentication 對象。

@GetMapping("/user-details")
public String userDetails(Authentication authentication) {
    return "User: " + authentication.getName() + ", Roles: " + authentication.getAuthorities();
}

4.6. hasPermission() API 文檔</h3

hasPermission()表達式是 Spring Security 的 ACL 系統的一部分,允許對領域對象進行精細化的權限檢查。它與僅檢查角色(例如hasRole('ADMIN'))不同,而是驗證特定資源上的權限。

例如,我們可以強制只有具有isEditor權限的用户才能批准文章:

@PreAuthorize("hasPermission(#article, 'isEditor')")
public void acceptArticle(Article article) {
   ...
}

為了使用 <em >hasPermission</em >,我們必須配置一個自定義的 <em >PermissionEvaluator</em >>。這個評估器定義瞭如何針對不同的對象檢查權限:

@Override
protected MethodSecurityExpressionHandler expressionHandler() {
    DefaultMethodSecurityExpressionHandler expressionHandler = 
      new DefaultMethodSecurityExpressionHandler();
    expressionHandler.setPermissionEvaluator(new CustomInterfaceImplementation());
    return expressionHandler;
}

5. 基於方法的安全控制,使用 @PreAuthorize@PostAuthorize

Spring Security 也允許我們在方法級別應用安全表達式。通過使用 @PreAuthorize@PostAuthorize,我們可以執行方法執行之前或之後的安全檢查。這在基於角色或其他條件來保護服務時尤其有用。

以下示例確保只有擁有 ADMIN 角色的用户才能執行 deleteUser() 方法:

@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(User user) {
    // Method logic
}

相反,@PostAuthorize() 確保方法執行後,用户只能查看自己的用户對象。

@PostAuthorize("returnObject.owner == authentication.name")
public User getUser(Long id) {
    // Fetch the user and return
}

6. 路徑變量和 @PreFilter / @PostFilter

Spring Security 也支持使用 @PreFilter@PostFilter 註解在方法中過濾集合。這在我們需要在方法執行之前或之後,根據已登錄用户的權限或其他條件進行過濾數據時非常有用。

@PreFilter 註解確保僅將集合中的某些元素傳遞給方法,在執行之前過濾掉未授權的元素:

@PreFilter("filterObject.owner == authentication.name")
public void updatePosts(List<Post> posts) {
    // Update posts for the user
}

表達式 filterObject.owner == authentication.name 確保僅處理屬於已登錄用户 (authentication.name) 的帖子。

@PostFilter 註解確保在執行後僅返回允許的元素給調用者。這在檢索數據時,限制訪問僅授權項目時非常有用。 讓我們來看一個例子:

@PostFilter("filterObject.owner == authentication.name")
public List<Post> getPosts() {
    // Get all the posts and ret
}

@PostFilter 註解會過濾掉不屬於當前已認證用户的所有帖子。

7. 結論

在本文中,我們探討了 Spring Security 表達式及其在保護 Web 應用程序中的應用。 通過利用諸如 hasRole()hasAuthority()permitAll() 等表達式,我們可以對應用程序的安全性進行精細調整。 此外,使用 @PreAuthorize@PostAuthorize@PreFilter@PostFilter 允許我們對方法級別的安全性以及數據過濾進行更精細的控制。

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

發佈 評論

Some HTML is okay.