Spring Security 的方法級權限控制是如何利用 AOP 的?

Spring Security 的方法級權限控制是 AOP 技術在實際應用中一個極其強大的應用典范。它允許我們以聲明式的方式保護業務方法,將安全規則與業務邏輯徹底解耦。

核心思想:權限檢查的“門衛”

你可以把 AOP 在方法級安全中的作用想象成一個盡職盡責的“門衛”。

  • 目標方法 (deleteUser): 一個重要的、需要保護的房間。
  • 調用方 (Caller): 想要進入這個房間的人。
  • 權限注解 (@PreAuthorize, @Secured): 貼在門上的“入內規則”(例如,“僅限管理員入內”)。
  • AOP 代理 (Proxy): 站在門口的門衛

當有人想進入房間時,他接觸到的不是房間本身,而是門衛。門衛會先查看門上的規則,然后檢查這個人的身份(權限)。如果符合規則,就放行;如果不符合,就直接把他攔在門外,這個人根本沒機會進入房間。


實現原理:AOP 攔截與決策

整個過程是通過一個特殊的 AOP 環繞通知 (@Around)前置通知 (@Before) 來實現的,這個通知就是 Spring Security 提供的 MethodSecurityInterceptor

Step 1: 開啟方法級安全

首先,你需要在你的配置類中開啟方法級安全的功能。

import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;@EnableGlobalMethodSecurity(prePostEnabled = true, // 啟用 @PreAuthorize 和 @PostAuthorizesecuredEnabled = true, // 啟用 @Securedjsr250Enabled = true   // 啟用 @RolesAllowed
)
public class MethodSecurityConfig {// ...
}

@EnableGlobalMethodSecurity 這個注解告訴 Spring:“請開始掃描帶有方法級安全注解的 Bean,并為它們應用 AOP 增強。”

Step 2: AOP 代理創建

@Transactional 一樣,當 Spring 容器發現一個 Bean (例如 AdminService) 的方法上帶有 @PreAuthorize 等注解時,它不會直接使用原始的 AdminService 實例。相反,它會:

  1. AdminService 創建一個 AOP 代理對象
  2. 這個代理對象中織入了 MethodSecurityInterceptor
  3. 容器中最終存在的是這個被增強了的代理對象。
Step 3: 方法調用與安全攔截 (核心)

當你的代碼調用一個被保護的方法時(例如 adminServiceProxy.deleteUser(1L)),流程如下:

  1. 調用被代理攔截
    調用首先命中代理對象

  2. MethodSecurityInterceptor 被激活
    這個安全攔截器開始工作,它的邏輯可以看作一個前置通知(對于 @PreAuthorize)或環繞通知

    a. 【方法執行前】進行權限決策:
    * 攔截器會查找當前被調用方法上的安全注解,例如 @PreAuthorize("hasRole('ADMIN')")
    * 它會從 SecurityContextHolder 中獲取當前用戶的 Authentication 對象,這個對象包含了用戶的身份信息和擁有的權限(如角色、權限字符串等)。
    * 它會使用 SpEL (Spring Expression Language) 解析器來執行注解中的表達式,例如 hasRole('ADMIN')
    * 解析器會拿當前用戶的權限和表達式進行比對。

    b. 【做出決策】放行或拒絕:
    * 如果表達式評估為 true (權限匹配)
    攔截器認為檢查通過,就會繼續執行調用鏈,最終調用到你原始的 AdminServicedeleteUser 業務邏輯方法。
    * 如果表達式評估為 false (權限不足)
    攔截器會立即中斷調用鏈直接拋出一個 AccessDeniedException (訪問被拒絕異常)。你的核心業務方法 deleteUser 根本不會被執行

    c. 異常處理:
    * 這個 AccessDeniedException 會被 Spring Security 的異常處理機制捕獲,通常會向客戶端返回一個 403 Forbidden 的 HTTP 狀態碼。

圖解實現原理

+----------------+
| Caller         |
+----------------+| 1. 調用 adminService.deleteUser()v
+--------------------------------------------------------------------------+
|              AdminService 代理對象 (Proxy)                               |
|                                                                          |
|   +------------------------------------------------------------------+   |
|   |          MethodSecurityInterceptor (AOP Advice)                  |   |
|   |                                                                  |   |
|   |    2. 【方法執行前】                                               |   |
|   |       - 查找注解: @PreAuthorize("hasRole('ADMIN')")                |   |
|   |       - 獲取當前用戶權限 (from SecurityContext)                    |   |
|   |       - 評估表達式: hasRole('ADMIN') ?                           |   |
|   |                                                                  |   |
|   |    3a. 【權限匹配】if (true) {                                    |   |
|   |            繼續調用 -> target.deleteUser() --> [核心業務邏輯]      |   |
|   |        }                                                         |   |
|   |                                                                  |   |
|   |    3b. 【權限不足】if (false) {                                   |   |
|   |            throw new AccessDeniedException();  <-- 中斷流程       |   |
|   |        }                                                         |   |
|   |                                                                  |   |
|   +------------------------------------------------------------------+   |
|                                                                          |
+--------------------------------------------------------------------------+^                                                               || 4. (成功) 返回結果 or (失敗) AccessDeniedException             ||                                                               |+---------------------------------------------------------------+

代碼示例

@Service
public class DocumentService {// 只有擁有 'ROLE_ADMIN' 角色或 'WRITE_DOCUMENT' 權限的用戶才能調用@PreAuthorize("hasRole('ADMIN') or hasAuthority('WRITE_DOCUMENT')")public void editDocument(String docId) {System.out.println("Executing: Editing document " + docId);// ... 核心業務邏輯 ...}// @PostAuthorize: 在方法執行后進行權限檢查,可以基于返回值進行判斷// 只有當返回的文檔所有者是當前用戶時,才允許返回@PostAuthorize("returnObject.owner == authentication.name")public Document getDocument(String docId) {System.out.println("Executing: Fetching document " + docId);// ... 從數據庫獲取文檔 ...return findDocumentInDb(docId); }
}

總結

  • 核心技術:Spring AOP 的前置通知環繞通知
  • 關鍵角色
    • @EnableGlobalMethodSecurity: AOP 功能的“總開關”。
    • 代理對象 (Proxy):攔截方法調用。
    • MethodSecurityInterceptor: 實現了具體的安全檢查邏輯。
    • SecurityContextHolder: 提供當前用戶的認證和權限信息。
  • 工作流程
    1. 代理攔截:調用被代理對象攔截。
    2. 權限檢查:在目標方法執行前,攔截器根據注解和當前用戶權限進行決策。
    3. 放行或中斷:如果權限足夠,則執行業務方法;如果不足,則直接拋出異常,中斷執行。

通過 AOP,Spring Security 將復雜的權限校驗邏輯從業務代碼中優雅地分離出去,使得代碼更加清晰、安全規則更易于管理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/912269.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/912269.shtml
英文地址,請注明出處:http://en.pswp.cn/news/912269.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一鍵內網穿透,無需域名和服務器,自動https訪問

cloudflare能將內網web轉為外網可訪問的地址。&#xff08;這和apiSQL有點類似&#xff0c;apiSQ可以將內網數據庫輕松轉換為外網的API&#xff0c;并且還支持代理內網已有API&#xff0c;增強安全增加API Key&#xff0c;以https訪問等等&#xff09; 但Cloudfalre tunnel這個…

Sentinel(二):Sentinel流量控制

一、Sentinel 流控規則基本介紹 1、Snetinel 流控規則配置方式 Sentinel 支持可視化的流控規則配置&#xff0c;使用非常簡單&#xff1b;可以在監控服務下的“簇點鏈路” 或 “流控規則” 中 給指定的請求資源配置流控規則&#xff1b;一般推薦在 “簇點鏈路” 中配置流控規則…

支持PY普冉系列單片機調試工具PY32linK仿真器

PY32 Link是專為 ?PY32系列ARM-Cortex內核單片機?&#xff08;如PY32F002A/030/071/040/403等&#xff09;設計的仿真器&#xff0c;支持全系列芯片的?調試和仿真?功能。?開發環境兼容性?支持主流IDE&#xff1a;?Keil MDK? 和 ?IAR Embedded Workbench?&#xff0c;…

深入解析Python多服務器監控告警系統:從原理到生產部署

深入解析Python多服務器監控告警系統&#xff1a;從原理到生產部署 整體架構圖 核心設計思想 無代理監控&#xff1a;通過SSH直接獲取數據&#xff0c;無需在目標服務器安裝代理故障隔離&#xff1a;單臺服務器故障不影響整體監控多級檢測&#xff1a;網絡層→資源層→服務層層…

JUC:10.線程、monitor管程、鎖對象之間在synchronized加鎖的流程(未完)

一、monitor管程工作原理&#xff1a; 首先&#xff0c;synchronized是一個對象鎖&#xff0c;當線程運行到某個臨界區&#xff0c;這個臨界區使用synchronized對對象obj進行了上鎖&#xff0c;此時底層發生了什么&#xff1f; 1.當synchronized對obj上鎖后&#xff0c;synch…

Elasticsearch(ES)分頁

Elasticsearch&#xff08;簡稱 ES&#xff09;本身不適合傳統意義上的“深分頁”&#xff0c;但提供了多種分頁方式&#xff0c;每種適用不同場景。我們來詳細講解&#xff1a; 一、基本分頁&#xff08;from size&#xff09; 最常用的分頁方式&#xff0c;類似 SQL 的 LIM…

原生微信小程序:用 `setData` 正確修改數組中的對象項狀態(附實戰技巧)

&#x1f4cc; 背景介紹 在微信小程序開發中&#xff0c;我們經常需要修改數組中某個對象的某個字段&#xff0c;比如&#xff1a; 列表中的某一項展開/收起多選狀態切換數據列表中的臨時標記等 一個常見的場景是&#xff1a; lists: [{ show: true }, { show: true }, { s…

Oracle 臨時表空間相關操作

一、臨時表空間概述 臨時表空間&#xff08;Temporary Tablespace&#xff09;是Oracle數據庫中用于存儲臨時數據的特殊存儲區域&#xff0c;其數據在會話結束或事務提交后自動清除&#xff0c;重啟數據庫后徹底消失。主要用途包括&#xff1a; 存儲排序操作&#xff08;如OR…

從靜態到動態:Web渲染模式的演進和突破

渲染模式有好多種&#xff0c;了解下web的各種渲染模式&#xff0c;對技術選型有很大的參考作用。 一、靜態HTML時代 早期&#xff08;1990 - 1995年&#xff09;網頁開發完全依賴手工編寫HTML&#xff08;HyperText Markup Language&#xff09;和CSS&#xff08;層疊樣式表…

Flask(六) 數據庫操作SQLAlchemy

文章目錄 一、準備工作二、最小化可運行示例? 補充延遲綁定方式&#xff08;推薦方式&#xff09; 三、數據庫基本操作&#xff08;增刪改查&#xff09;1. 插入數據&#xff08;增&#xff09;2. 查詢數據&#xff08;查&#xff09;3. 更新數據&#xff08;改&#xff09;4.…

PYTHON從入門到實踐7-獲取用戶輸入與while循環

# 【1】獲取用戶輸入 # 【2】python數據類型的轉換 input_res input("請輸入一個數字\n") if int(input_res) % 10 0:print("你輸入的數是10的倍數") else:print("你輸入的數不是10的倍數") # 【3】while循環&#xff0c;適合不知道循環多少次…

學習筆記(C++篇)—— Day 8

1.STL簡介 STL(standard template libaray-標準模板庫)&#xff1a;是C標準庫的重要組成部分&#xff0c;不僅是一個可復用的組件庫&#xff0c;而且是一個包羅數據結構與算法的軟件框架。 2.STL的六大組件 先這樣&#xff0c;下一部分是string的內容&#xff0c;內容比較多&a…

ant+Jmeter+jenkins接口自動化,如何實現把執行失敗的接口信息單獨發郵件?

B站講的最好的自動化測試教程&#xff0c;工具框架附項目實戰一套速通&#xff0c;零基礎完全輕松掌握&#xff01;自動化測試課程、web/app/接口 實現AntJMeterJenkins接口自動化失敗接口郵件通知方案 要實現只發送執行失敗的接口信息郵件通知&#xff0c;可以通過以下步驟實…

惡意Python包“psslib“實施拼寫錯誤攻擊,可強制關閉Windows系統

Socket威脅研究團隊發現一個名為psslib的惡意Python包&#xff0c;該軟件包偽裝成提供密碼安全功能&#xff0c;實則會突然關閉Windows系統。這個由化名umaraq的威脅行為者開發的軟件包&#xff0c;是對知名密碼哈希工具庫passlib的拼寫錯誤仿冒&#xff08;typosquatting&…

云原生灰度方案對比:服務網格灰度(Istio ) 與 K8s Ingress 灰度(Nginx Ingress )

服務網格灰度與 Kubernetes Ingress 灰度是云原生環境下兩種主流的灰度發布方案&#xff0c;它們在架構定位、實現方式和適用場景上存在顯著差異。以下從多個維度對比分析&#xff0c;并給出選型建議&#xff1a; 一、核心區別對比 維度服務網格灰度&#xff08;以 Istio 為例…

科技如何影響我們的生活?

科技已成為我們生活中不可或缺的一部分&#xff0c;徹底改變了我們工作、溝通和生活的方式。從智能手機到智能家居&#xff0c;科技已滲透到我們生活的每個角落。無論是用手機鬧鐘開啟新的一天&#xff0c;通過 Alexa 開關燈光&#xff0c;還是打開 Uber 或 Lyft 打車上班&…

Re--攻防世界-基礎android

Jadx 可以看到有賬號密碼輸入 進入checkPassword函數 分析一下&#xff1a; 對每個字符 pass[len] 進行以下計算 pass[len] (char) (((255 - len) - 100) - pass[len]); 解密腳本 def decrypt_password(): password [] for len in range(12): c (255 - le…

InnoDB表空間結構-系統表空間

系統表空間整體結構 頁號為7的SYS類型頁結構

如何構建知識庫

構建個人知識庫是一個系統化的過程&#xff0c;需要結合工具選擇、信息管理和持續優化。以下是分步驟的實用指南&#xff0c;包含現代工具和方法的建議&#xff1a; 一、明確知識庫定位&#xff08;Why&#xff09; ?核心目標? 學習型&#xff1a;支持學術研究/職業發展&…

3 大語言模型預訓練數據-3.2 數據處理-3.2.2 冗余去除——2.SimHash算法文本去重實戰案例:新聞文章去重場景

SimHash算法文本去重實戰案例&#xff1a;新聞文章去重場景 一、案例背景與目標二、具體實現步驟與示例1. **待去重文本示例**2. **步驟1&#xff1a;文本預處理與特征提取**3. **步驟2&#xff1a;特征向量化與哈希映射**4. **步驟3&#xff1a;特征向量聚合**5. **步驟4&…