欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringSecurity攔截器鏈的使用詳解

 更新時間:2023年11月21日 10:25:21   作者:dalianpai  
這篇文章主要介紹了SpringSecurity攔截器鏈的使用詳解,webSecurity的build方法最終調用的是doBuild方法,doBuild方法調用的是webSecurity的performBuild方法,webSecurity完成所有過濾器的插件,最終返回的是過濾器鏈代理類filterChainProxy,需要的朋友可以參考下

SpringSecurity攔截器鏈

Spring版本

<!--Spring Security過濾器鏈,注意過濾器名稱必須叫springSecurityFilterChain-->
<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>

SpringBoot 版本

攔截器鏈創(chuàng)建的過程

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
		SpringWebMvcImportSelector.class,
		OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
 
	/**
	 * Controls debugging support for Spring Security. Default is false.
	 * @return if true, enables debug support with Spring Security
	 */
	boolean debug() default false;
}

當我們使用這個注解的時候,等同于把WebSecurityConfiguration類放到了Spring的IOC容器中,在這個時候進行了初始化。

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public Filter springSecurityFilterChain() throws Exception {
		boolean hasConfigurers = webSecurityConfigurers != null
				&& !webSecurityConfigurers.isEmpty();
		if (!hasConfigurers) {
			WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
					.postProcess(new WebSecurityConfigurerAdapter() {
					});
			webSecurity.apply(adapter);
		}
        //調用webSecurity的build方法,生成過濾器鏈。
		return webSecurity.build();
	}

webSecurity的build方法最終調用的是doBuild方法。

public final O build() throws Exception {
		if (this.building.compareAndSet(false, true)) {
			this.object = doBuild();
			return this.object;
		}
		throw new AlreadyBuiltException("This object has already been built");
	}

doBuild方法調用的市webSecurity的performBuild方法。

@Override
	protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;
 
			beforeInit();
			init();
 
			buildState = BuildState.CONFIGURING;
 
			beforeConfigure();
			configure();
 
			buildState = BuildState.BUILDING;
            //在BUILDING階段調用webSecurity的performBuild方法
			O result = performBuild();
 
			buildState = BuildState.BUILT;
 
			return result;
		}
	}

webSecurity完成所有過濾器的插件,最終返回的是過濾器鏈代理類filterChainProxy

@Override
	protected Filter performBuild() throws Exception {
		Assert.state(
				!securityFilterChainBuilders.isEmpty(),
				() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
						+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
						+ "More advanced users can invoke "
						+ WebSecurity.class.getSimpleName()
						+ ".addSecurityFilterChainBuilder directly");
		int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
				chainSize);
        //會創(chuàng)建要忽略的和要認證的攔截器鏈
		for (RequestMatcher ignoredRequest : ignoredRequests) {
			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
			securityFilterChains.add(securityFilterChainBuilder.build());
		}
        //過濾器鏈實際是被filterChainProxy代理的
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		if (httpFirewall != null) {
			filterChainProxy.setFirewall(httpFirewall);
		}
		filterChainProxy.afterPropertiesSet();
 
		Filter result = filterChainProxy;
		if (debugEnabled) {
			logger.warn("\n\n"
					+ "********************************************************************\n"
					+ "**********        Security debugging is enabled.       *************\n"
					+ "**********    This may include sensitive information.  *************\n"
					+ "**********      Do not use in a production system!     *************\n"
					+ "********************************************************************\n\n");
			result = new DebugFilter(filterChainProxy);
		}
		postBuildAction.run();
		return result;
	}

斷點圖如下:

image-20210508162350146

FilterChainProxy間接繼承了Filter,可以作為真正的過濾器使用。它會攜帶若干條過濾器鏈,并在承擔過濾器職責,將其派發(fā)到過濾器鏈上的每一個過濾器上。

Override
	public 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);
                //派發(fā)到過濾器鏈上
				doFilterInternal(request, response, chain);
			}
			finally {
				SecurityContextHolder.clearContext();
				request.removeAttribute(FILTER_APPLIED);
			}
		}
		else {
			doFilterInternal(request, response, chain);
		}
	}
    //是真正執(zhí)行虛擬過濾器鏈邏輯的方法。
	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);
	}

image-20210508165318181

private VirtualFilterChain(FirewalledRequest firewalledRequest,
				FilterChain chain, List<Filter> additionalFilters) {
			this.originalChain = chain;
			this.additionalFilters = additionalFilters;
			this.size = additionalFilters.size();
			this.firewalledRequest = firewalledRequest;
		}
 
		@Override
		public 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 chain
				this.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);
			}
		}

請求的過程

ApplicationFilterChain是tomcat中的攔截器鏈,ApplicationFilterChain對象的特點與創(chuàng)建特點:經過一路代碼跟蹤發(fā)現,每一個url匹配模式對應于一個ApplicationFilterChain對象,在應用的整個生命周期中只在第一次被訪問時被創(chuàng)建一次,有種單例模式的感覺,但是并沒有做線程安全方面的處理,后來發(fā)現可能做了池化處理;創(chuàng)建:ApplicationFilterChain對象是在StandardWrapperValve類中的invoke方法中調ApplicationFilterFactory.createFilterChain方法創(chuàng)建的,在實例化完成后緊接著就是為其設置Servlet,添加Filters以及設置其他屬性,添加Filters依賴于一個FilterMap[]數組,該數組的賦值與擴容過程在StandardContext類中實現,至于FilterMap的生成,則是在Spring的Bean初始化階段,通過掃描包下所有的類并結合注解通過反射機制進行實例化的。

@Override
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
 
        if( Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            try {
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedExceptionAction<Void>() {
                        @Override
                        public Void run()
                            throws ServletException, IOException {
                            internalDoFilter(req,res);
                            return null;
                        }
                    }
                );
            } catch( PrivilegedActionException pe) {
                Exception e = pe.getException();
                if (e instanceof ServletException)
                    throw (ServletException) e;
                else if (e instanceof IOException)
                    throw (IOException) e;
                else if (e instanceof RuntimeException)
                    throw (RuntimeException) e;
                else
                    throw new ServletException(e.getMessage(), e);
            }
        } else {
            internalDoFilter(request,response);
        }
    }
 
private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {
 
        // Call the next filter if there is one
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();
 
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                }
                if( Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                        ((HttpServletRequest) req).getUserPrincipal();
 
                    Object[] args = new Object[]{req, res, this};
                    SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
                } else {
                    filter.doFilter(request, response, this);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                sthrow new ServletException(sm.getString("filterChain.filter"), e);
            }
            return;
        }

其中會優(yōu)先調用springsecurity的攔截器鏈,它的本質還是有一個fiter,注意,這里第5個過濾器顯示在攔截器鏈后執(zhí)行的,但是在攔截器鏈里面執(zhí)行過了,就不會這執(zhí)行了。

image-20210508161226433

當請求到攔截鏈的時候

image-20210508161452455

依次執(zhí)行過濾器鏈

image-20210508161551528

到此這篇關于SpringSecurity攔截器鏈的使用詳解的文章就介紹到這了,更多相關SpringSecurity攔截器鏈內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • websocket在springboot+vue中的使用教程

    websocket在springboot+vue中的使用教程

    這篇文章主要介紹了websocket在springboot+vue中的使用教程,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • Spring的循環(huán)依賴、三級緩存解決方案源碼詳細解析

    Spring的循環(huán)依賴、三級緩存解決方案源碼詳細解析

    這篇文章主要介紹了Spring的循環(huán)依賴、三級緩存解決方案源碼詳細解析,在Spring中,由于IOC的控制反轉,創(chuàng)建對象不再是簡單的new出來,而是交給Spring去創(chuàng)建,會經歷一系列Bean的生命周期才創(chuàng)建出相應的對象,需要的朋友可以參考下
    2024-01-01
  • SpringBoot4.5.2 整合HikariCP 數據庫連接池操作

    SpringBoot4.5.2 整合HikariCP 數據庫連接池操作

    這篇文章主要介紹了SpringBoot4.5.2 整合HikariCP 數據庫連接池操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java中throws與try...catch的區(qū)別點

    java中throws與try...catch的區(qū)別點

    在本篇文章里小編給大家整理了一篇關于java中throws與try...catch的區(qū)別點的內容,需要的朋友們跟著學習下。
    2020-02-02
  • 使用Java如何將文本復制到剪貼板

    使用Java如何將文本復制到剪貼板

    這篇文章主要介紹了使用Java如何將文本復制到剪貼板問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • java多線程CyclicBarrier的使用案例,讓線程起步走

    java多線程CyclicBarrier的使用案例,讓線程起步走

    這篇文章主要介紹了java多線程CyclicBarrier的使用案例,讓線程起步走!具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Spring AI 文檔的提取、轉換、加載功能實現

    Spring AI 文檔的提取、轉換、加載功能實現

    Spring AI 是一個基于 Spring 生態(tài)系統的框架,旨在簡化人工智能和機器學習模型的集成,本文將介紹如何使用 Spring AI 和 Apache Tika 構建一個簡單的 ETL 管道,特別是如何利用?spring-ai-tika-document-reader?依賴來處理和轉換文檔數據,感興趣的朋友一起看看吧
    2024-11-11
  • Java線程池ForkJoinPool實例解析

    Java線程池ForkJoinPool實例解析

    這篇文章主要介紹了Java線程池ForkJoinPool實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • 詳解Springboot配置文件的使用

    詳解Springboot配置文件的使用

    在springboot項目中,也可以使用yml類型的配置文件代替properties文件。接下來通過本文給大家分享Springboot配置文件的使用,感興趣的朋友一起看看吧
    2017-07-07
  • spring的pointcut正則表達式的實現

    spring的pointcut正則表達式的實現

    本文主要介紹了spring的pointcut正則表達式的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08

最新評論