SpringSecurity源碼分析-過濾器鏈是如何植入到spring中的

SpringSecurity源碼分析-過濾器鏈是如何植入到spring中的

一切的源頭都是因為在web.xml中配置了這樣一個Filter

<!--security--><filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping>

DelegatingFilterProxy中加載FilterChainProxy

  1. 這是一個模板類,是一個過濾器鏈代理對象,SpringSecurity中的FilterChainProxy通過這個過濾器植入進來
  2. DelegatingFilterProxy是對外提供的,用于植入外部過濾器鏈的類
  3. FilterChainProxy在這個類中被植入Spring中.
public class DelegatingFilterProxy extends GenericFilterBean {@Nullableprivate String contextAttribute;@Nullableprivate WebApplicationContext webApplicationContext;@Nullableprivate String targetBeanName;private boolean targetFilterLifecycle;@Nullable/** 真實的過濾器 */private volatile Filter delegate;private final Object delegateMonitor;public DelegatingFilterProxy() {this.targetFilterLifecycle = false;this.delegateMonitor = new Object();}public DelegatingFilterProxy(Filter delegate) {this.targetFilterLifecycle = false;this.delegateMonitor = new Object();Assert.notNull(delegate, "Delegate Filter must not be null");this.delegate = delegate;}public DelegatingFilterProxy(String targetBeanName) {this(targetBeanName, (WebApplicationContext)null);}public DelegatingFilterProxy(String targetBeanName, @Nullable WebApplicationContext wac) {this.targetFilterLifecycle = false;this.delegateMonitor = new Object();Assert.hasText(targetBeanName, "Target Filter bean name must not be null or empty");this.setTargetBeanName(targetBeanName);this.webApplicationContext = wac;if (wac != null) {this.setEnvironment(wac.getEnvironment());}}public void setContextAttribute(@Nullable String contextAttribute) {this.contextAttribute = contextAttribute;}@Nullablepublic String getContextAttribute() {return this.contextAttribute;}public void setTargetBeanName(@Nullable String targetBeanName) {this.targetBeanName = targetBeanName;}@Nullableprotected String getTargetBeanName() {return this.targetBeanName;}public void setTargetFilterLifecycle(boolean targetFilterLifecycle) {this.targetFilterLifecycle = targetFilterLifecycle;}protected boolean isTargetFilterLifecycle() {return this.targetFilterLifecycle;}/** 這個方法在父類的init方法中調用,這個方法構造真實的過濾器*/protected void initFilterBean() throws ServletException {synchronized(this.delegateMonitor) {if (this.delegate == null) {if (this.targetBeanName == null) {this.targetBeanName = this.getFilterName();}WebApplicationContext wac = this.findWebApplicationContext();if (wac != null) {this.delegate = this.initDelegate(wac);}}}}public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {Filter delegateToUse = this.delegate;if (delegateToUse == null) {synchronized(this.delegateMonitor) {delegateToUse = this.delegate;if (delegateToUse == null) {WebApplicationContext wac = this.findWebApplicationContext();if (wac == null) {throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");}delegateToUse = this.initDelegate(wac);}this.delegate = delegateToUse;}}/** 調用真實過濾器中的doFilter方法*/this.invokeDelegate(delegateToUse, request, response, filterChain);}public void destroy() {Filter delegateToUse = this.delegate;if (delegateToUse != null) {this.destroyDelegate(delegateToUse);}}@Nullableprotected WebApplicationContext findWebApplicationContext() {if (this.webApplicationContext != null) {if (this.webApplicationContext instanceof ConfigurableApplicationContext) {ConfigurableApplicationContext cac = (ConfigurableApplicationContext)this.webApplicationContext;if (!cac.isActive()) {cac.refresh();}}return this.webApplicationContext;} else {String attrName = this.getContextAttribute();return attrName != null ? WebApplicationContextUtils.getWebApplicationContext(this.getServletContext(), attrName) : WebApplicationContextUtils.findWebApplicationContext(this.getServletContext());}}/** 獲取過濾器鏈 springSecurityFilterChain*/protected Filter initDelegate(WebApplicationContext wac) throws ServletException {String targetBeanName = this.getTargetBeanName();Assert.state(targetBeanName != null, "No target bean name set");/** 根據名字和類型獲取獲取過濾器鏈,這里的targetBeanName即springSecurityFilterChain,這個是在Spring中寫死的,自動裝配的..*/Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);if (this.isTargetFilterLifecycle()) {delegate.init(this.getFilterConfig());}return delegate;}protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {delegate.doFilter(request, response, filterChain);}protected void destroyDelegate(Filter delegate) {if (this.isTargetFilterLifecycle()) {delegate.destroy();}}
}

小結:通過過濾器鏈代理對象DelegatingFilterProxy找到真正的過濾器鏈FilterChainProxy,然后去一個一個的過濾器去處理請求

FilterChainProxy

  1. private List filterChains 存儲過濾器鏈
  2. doFilter方法中調用doFilterInternal方法
  3. 獲取到所有的過濾器,挨個執行filter的filter方法
public class FilterChainProxy extends GenericFilterBean {// ~ Static fields/initializers// =====================================================================================private static final Log logger = LogFactory.getLog(FilterChainProxy.class);// ~ Instance fields// ================================================================================================private final static String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");/**存儲過濾器鏈**/private List<SecurityFilterChain> filterChains;private FilterChainValidator filterChainValidator = new NullFilterChainValidator();private HttpFirewall firewall = new StrictHttpFirewall();// ~ Methods// ========================================================================================================public FilterChainProxy() {}public FilterChainProxy(SecurityFilterChain chain) {this(Arrays.asList(chain));}public FilterChainProxy(List<SecurityFilterChain> filterChains) {this.filterChains = filterChains;}@Overridepublic void afterPropertiesSet() {filterChainValidator.validate(this);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;if (clearContext) {try {request.setAttribute(FILTER_APPLIED, Boolean.TRUE);doFilterInternal(request, response, chain);}finally {SecurityContextHolder.clearContext();request.removeAttribute(FILTER_APPLIED);}}else {doFilterInternal(request, response, chain);}}private void doFilterInternal(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) request);HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);/** 獲取過濾器 */List<Filter> filters = getFilters(fwRequest);if (filters == null || filters.size() == 0) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(fwRequest)+ (filters == null ? " has no matching filters": " has an empty filter list"));}fwRequest.reset();/** 挨個執行過濾器*/chain.doFilter(fwRequest, fwResponse);return;}VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);vfc.doFilter(fwRequest, fwResponse);}/*** Returns the first filter chain matching the supplied URL.** @param request the request to match* @return an ordered array of Filters defining the filter chain*/private List<Filter> getFilters(HttpServletRequest request) {for (SecurityFilterChain chain : filterChains) {if (chain.matches(request)) {return chain.getFilters();}}return null;}/*** Convenience method, mainly for testing.** @param url the URL* @return matching filter list*/public List<Filter> getFilters(String url) {return getFilters(firewall.getFirewalledRequest((new FilterInvocation(url, "GET").getRequest())));}/*** @return the list of {@code SecurityFilterChain}s which will be matched against and* applied to incoming requests.*/public List<SecurityFilterChain> getFilterChains() {return Collections.unmodifiableList(filterChains);}/*** Used (internally) to specify a validation strategy for the filters in each* configured chain.** @param filterChainValidator the validator instance which will be invoked on during* initialization to check the {@code FilterChainProxy} instance.*/public void setFilterChainValidator(FilterChainValidator filterChainValidator) {this.filterChainValidator = filterChainValidator;}/*** Sets the "firewall" implementation which will be used to validate and wrap (or* potentially reject) the incoming requests. The default implementation should be* satisfactory for most requirements.** @param firewall*/public void setFirewall(HttpFirewall firewall) {this.firewall = firewall;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("FilterChainProxy[");sb.append("Filter Chains: ");sb.append(filterChains);sb.append("]");return sb.toString();}// ~ Inner Classes// ==================================================================================================/*** Internal {@code FilterChain} implementation that is used to pass a request through* the additional internal list of filters which match the request.*/private static class VirtualFilterChain implements FilterChain {private final FilterChain originalChain;private final List<Filter> additionalFilters;private final FirewalledRequest firewalledRequest;private final int size;private int currentPosition = 0;private VirtualFilterChain(FirewalledRequest firewalledRequest,FilterChain chain, List<Filter> additionalFilters) {this.originalChain = chain;this.additionalFilters = additionalFilters;this.size = additionalFilters.size();this.firewalledRequest = firewalledRequest;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if (currentPosition == size) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " reached end of additional filter chain; proceeding with original chain");}// Deactivate path stripping as we exit the security filter chainthis.firewalledRequest.reset();originalChain.doFilter(request, response);}else {currentPosition++;Filter nextFilter = additionalFilters.get(currentPosition - 1);if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " at position " + currentPosition + " of " + size+ " in additional filter chain; firing Filter: '"+ nextFilter.getClass().getSimpleName() + "'");}nextFilter.doFilter(request, response, this);}}}public interface FilterChainValidator {void validate(FilterChainProxy filterChainProxy);}private static class NullFilterChainValidator implements FilterChainValidator {@Overridepublic void validate(FilterChainProxy filterChainProxy) {}}}

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

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

相關文章

NoSQL 之 Redis 集群部署

前言&#xff1a; &#xff08;1&#xff09;主從復制&#xff1a;主從復制是高可用Redis的基礎&#xff0c;哨兵和集群都是在主從復制基礎上實現高可用 的。主從復制主要實現了數據的多機備份&#xff0c;以及對于讀操作的負載均衡和簡單的故障恢復。缺陷&#xff1a; 故障…

vue3+antd 實現文件夾目錄右鍵菜單功能

原本的目錄結構&#xff1a; 右鍵菜單&#xff1a; 點擊菜單以后會觸發回調&#xff1a; 完整的前端代碼&#xff1a; <template><a-directory-treev-model:expandedKeys"expandedKeys"v-model:selectedKeys"selectedKeys"multipleshow-li…

在 Docker 容器中運行 Vite 開發環境,有這兩個問題要注意

容器化開發給我們帶來了很多便捷&#xff0c;但是在開發環境下也有一些問題要注意&#xff0c;如果不解決這些問題&#xff0c;你的開發體驗不會很好。 容器啟動正常&#xff0c;卻無法訪問 我們用 Docker 啟動一個 Vite Vue3 項目的開發環境后&#xff0c;發現端口日志一切…

計算機如何存儲浮點數

浮點數組成 在計算機中浮點數通常由三部分組成&#xff1a;符號位、指數位、尾數位。IEEE-754中32位浮點數如下&#xff1a; 上圖32bit浮點數包含1bit的符號位&#xff0c;8比特的指數位和23bit的尾數位。對于一個常規浮點數&#xff0c;我們來看看它是如何存儲和計算的。這里…

conda env pip install error:No space left on device

conda 環境 pip install error&#xff1a;No space left on device 文章目錄 conda 環境 pip install error&#xff1a;No space left on device現象1 實驗2 分析和解決辦法 現象 非root用戶的服務器&#xff0c;需要安裝環境&#xff0c;安裝的環境超過2GB sudo pip insta…

醫療機器人中的具身智能進展——自主超聲策略模型的任務編碼和局部探索

醫療機器人一直是具身智能的研究熱點。醫學圖像、醫療觸診、血壓血氧、心率脈搏和生物電信號等多模態生物醫學信息&#xff0c;不斷豐富著醫療機器人的感知范疇。 自主超聲 “自主超聲”屬于具身智能醫療機器人領域中話題度較高的研究方向。作為臨床檢查的重要手段之一&#…

線性系統理論及應用GUI設計及仿真

目錄 1.控制系統的狀態空間模型 1.1.狀態空間模型 1.2 傳遞函數模型 1.3 傳遞函數轉換為狀態空間模型 1.4.狀態空間模型轉換為傳遞函數 1.5.狀態空間模型轉化為約當標準型 2.線性系統的時域分析 2.1.矩陣指數函數的計算 2.2.線型定常連續系統的狀態空間模型求解 3.線…

ubuntu24.04按關鍵字卸載不需要的apt包

使用的時候發現一個imagemagic無法正常讀取文件&#xff0c;試圖卸載 man apt經過嘗試后&#xff0c;發現list的一個神奇關鍵字&#xff0c;用來顯示已安裝的軟件包 sudo apt list --installed | grep image按image關鍵字過濾&#xff1a; 之后按軟件名卸載即可 sudo apt pu…

開關電源——調制模式和工作模式

一、開關電源的調制模式 開關電源作為一種廣泛應用于電子設備中&#xff0c;用于將一定電壓和電流轉換為另一種電壓和電流的技術&#xff0c;以下是開關電源三種常見的調制模式&#xff1a; 脈沖寬度調制&#xff08;Pulse Width Modulation&#xff09; 脈沖頻率調制&#xff…

上升與下降

目錄 開頭程序程序的流程圖關于上升與下降的動畫(程序的效果)結尾 開頭 大家好&#xff0c;我叫這是我58。今天&#xff0c;我們要來看一個關于上升與下降的動畫和這個動畫相關的內容。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #define HIGH 10 #include <stdio.h> #…

高德地圖 key 和安全密鑰使用

參考高德地圖&#xff1a;JS API 安全密鑰使用 高德地圖 key 和安全密鑰使用 一、通過明文方式設置參數查看如下成功后返回的信息 二、通過代理服務器轉發實驗&#xff1a;通過本地地址轉發返回錯的錯誤信息&#xff0c;如下通過正確的項目的的服務地址&#xff0c;返回正常參數…

【VUE基礎】VUE3第一節—vite創建vue3工程

什么是VUE Vue (發音為 /vju?/&#xff0c;類似 view) 是一款用于構建用戶界面的 JavaScript 框架。它基于標準 HTML、CSS 和 JavaScript 構建&#xff0c;并提供了一套聲明式的、組件化的編程模型&#xff0c;幫助你高效地開發用戶界面。無論是簡單還是復雜的界面&#xff0…

Java+MySQL8.0.36+ElementUI數字化產科信息管理系統之”五色管理”

JavaMySQL8.0.36ElementUI數字化產科信息管理系統之”五色管理” 一、數字化產科信息管理系統概述 數字化產科信息管理五色管理是一種基于孕產婦妊娠風險的分類管理方法&#xff0c;通過數字化手段實現孕產婦全周期的健康風險評估與管理。該方法將孕產婦按照風險等級分為綠色、…

DC-DC充放電原理

文章目錄 前言1. 電子器件1.1 電容1.2 電感 2. 升壓電路3. 降壓電路4. 電壓均衡電路4.1 被動均衡4.2 主動均衡 5. 我的疑問5.1 對于升壓電路&#xff0c;怎么設計升壓到多少V后&#xff0c;停止升壓&#xff1f;5.2 什么是等效電阻&#xff1f;5.3 快充是如何實現的&#xff1f…

紅外遙控:智能學習紅外遙控編碼

家用電器如電視、機頂盒、空調等都可以通過紅外遙控&#xff0c;Rainbow專為物聯網、家居智能而設計的硬件&#xff0c;自然在紅外遙控收發方面有很好的支持。 紅外遙控通常是由紅外發光二極管發射一定頻率的載波&#xff0c;通過載波攜帶的控制信息&#xff0c;經過調制的信號…

LightGlue: Local Feature Matching at Light Speed【文獻閱讀】

論文&#xff1a;LightGlue: Local Feature Matching at Light Speed 代碼&#xff1a;https://github.com/cvg/LightGlue 作者&#xff1a;1 ETH Zurich__2 Microsoft Mixed Reality & AI Lab Abstract 提出的LightGlue是一個深度神經網絡用于學習圖像間的局部特征匹配。…

back-end developer 后端開發的一些常識

通俗易懂版 1. 通信協議 1.1 RPC (Remote Procedure Call) 客觀解釋&#xff1a; RPC是一種協議&#xff0c;允許程序通過網絡在不同的計算機上調用函數&#xff0c;就像調用本地函數一樣。RPC隱藏了網絡通信的復雜性&#xff0c;使得遠程服務調用看起來像是本地調用。 現實…

WAIC | 上海人形機器人創新中心 | 最新演講 | 詳細整理

前言 筆者看了7月4號的人形機器人與具身智能發展論壇的直播&#xff0c;并在7月5日到了上海WAIC展會現場參觀。這次大會的舉辦很有意義&#xff0c;聽并看了各家的最新成果&#xff0c;拍了很多照片視頻&#xff0c;部分演講也錄屏了在重復觀看學習 稍后會相繼整理創立穹徹智…

算法系列--分治排序|歸并排序|逆序對的求解

一.基本概念與實現 歸并排序(mergeSort)也是基于分治思想的一種排序方式,思路如下: 分解:根據中間下標mid將數組分解為兩部分解決:不斷執行上述分解過程,當分解到只有一個元素時,停止分解,此時就是有序的合并:合并兩個有序的子區間,所有子區間合并的結果就是原問題的解 歸并…

第一節 網絡安全概述

一.網絡空間安全 網絡空間&#xff1a;一個由信息基礎設施組成相互依賴的網絡。 ---- 海陸空天&#xff08;大海、陸 地、天空、航天&#xff09; 通信保密階段 ---- 計算機安全 ----- 信息系統安全 ----- 網絡空間安全 計算機安全&#xff1a;開始秉持著“嚴于律己&#x…