Spring Security源碼解析(二.創建FilterChainProxy)

上一章介紹了Spring Security的相關知識點,這章將詳細分析源碼。

首先需要認識到Spring Security的關鍵是filter——FilterChainProxy,經過一層層的filter才能最終訪問到我們的資源信息。

同時要了解,訪問不同的uri,系統會採取對應的filter列表進行過濾,如下圖所示。

嚴謹點說不止是uri,可以自定義匹配頭信息啊或者其他的,http請求中可以用來區分的都可以做爲匹配條件。這裏爲了方便理解。

那麼Spring Security啓動的時候是如何加載這些filter和排序的呢?下面是訪問/login uri對應的FilterChain。

                                          

Spring Security filter配置與原理

上一章我們瞭解到,需要人爲配置WebSecurityConfigurerAdapter的繼承類,如下圖所示。注意到類上有註解@EnableWebSecurity。

@Configuration
   @EnableWebSecurity
   public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  
   	@Override
   	public void configure(WebSecurity web) throws Exception {
   		web.ignoring()
   		// Spring Security should completely ignore URLs starting with /resources/
   				.antMatchers("/resources/**");
   	}
  
   	@Override
   	protected void configure(HttpSecurity http) throws Exception {
   		http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest()
   				.hasRole("USER").and()
   				// Possibly more configuration ...
   				.formLogin() // enable form based log in
   				// set permitAll for all URLs associated with Form Login
   				.permitAll();
   	}
  
   	@Override
   	protected void configure(AuthenticationManagerBuilder auth) {
   		auth
   		// enable in memory based authentication with a user named "user" and "admin"
   		.inMemoryAuthentication().withUser("user").password("password").roles("USER")
   				.and().withUser("admin").password("password").roles("USER", "ADMIN");
   	}
  
   	// Possibly more overridden methods ...
   }

@EnableWebSecurity是用於初始化WebSecurityConfiguration.class和引入@EnableGloabalAuthentication等,源碼如下。

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
		SpringWebMvcImportSelector.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呢?它又有什麼用呢?在此之前先得了解幾個概念。

SecurityBuilder<O>

顧名思義是一個builder構造器,創建並返回一個類型爲O的對象,源碼如下

public interface SecurityBuilder<O> {

	/**
	 * Builds the object and returns it or null.
	 *
	 * @return the Object to be built or null if the implementation allows it.
	 * @throws Exception if an error occurred when building the Object
	 */
	O build() throws Exception;
}

它的實現類如下圖所示,可以看到很多熟悉的類。

                               

AbstractSecurityBuilder<O>核心方法有

  • build()
  • doBuild()
  • getObject()

源碼如下,AtomicBoolean.compareAndSet(false,true)限定build()只會進行一次!然後子類需要重寫的方法變爲doBuild()。

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
	private AtomicBoolean building = new AtomicBoolean();

	private O object;

	// 只會創建一次object
	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");
	}

	// 獲取object
	public final O getObject() {
		if (!this.building.get()) {
			throw new IllegalStateException("This object has not been built");
		}
		return this.object;
	}

	// 子類需要繼承doBuild()方法
	protected abstract O doBuild() throws Exception;
}

AbstractConfiguredSecurityBuilder<O,B extends SecurityBuilder<O>>  主要作用是將SpringConfigurer注入到屬性configurers中,然後重寫doBuild()方法遍歷configurers進行init()和configure()。

它的子類HttpSecurity和WebSecurity都沿用了它的doBuild()方法!!!即遍歷configures進行init()和configure()!!!

核心方法

  • apply(C configurer)
  • add(C configurer)
  • doBuild()
  • abstract performBuild()

核心屬性(WebSecurity,HttpSecurity都會沿用該重要屬性)

private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();

configurers是個LinkedHashMap,key爲class,value爲List<SecurityConfigurer<O,B>>,通過apply()方法將configure存入configures中。

public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
		add(configurer);
		return configurer;
	}


@SuppressWarnings("unchecked")
	private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
		Assert.notNull(configurer, "configurer cannot be null");

		Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
				.getClass();
		synchronized (configurers) {
            // buildState是個enum類,有幾個狀態如UNBUILT,INITIALIZING,CONFIGURING,BUILDING,BUILT
			if (buildState.isConfigured()) {
				throw new IllegalStateException("Cannot apply " + configurer
						+ " to already built object");
			}
			List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
					.get(clazz) : null;
			if (configs == null) {
				configs = new ArrayList<SecurityConfigurer<O, B>>(1);
			}
			configs.add(configurer);
            // put進configurers中
			this.configurers.put(clazz, configs);
			if (buildState.isInitializing()) {
				this.configurersAddedInInitializing.add(configurer);
			}
		}
	}

既然apply()方法將SecurityConfigurer注入了屬性configurers中,肯定要用到該屬性,下面就是核心代碼doBuild()

    // 重寫了AbstractSecurityBuilder方法
    @Override
	protected final O doBuild() throws Exception {
		synchronized (configurers) {
                    // 狀態=1
			buildState = BuildState.INITIALIZING;

			beforeInit();
                    // 遍歷configurers中所有configurer,分別執行init()創建SecurityBuilder<O>
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
                    // 遍歷後執行各個實現類的configure()方法
			configure();

			buildState = BuildState.BUILDING;

                    // abstract方法,獲取build後的值
			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

SecurityConfigurer<O,B extends SecurityBuilder<O>>

一句話概括:初始化(init)SecurityBuilder,且配置(configure)SecurityBuilder

/**
* 初始化B,且配置B的相關屬性
* B SecurityBuilder<O>的子類
* O B.build()返回的object類型
*/
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
	/**
     * 初始化SecurityBuilder<O>	
     * 只創建設置了共享的變量,不會設置configure()中需要的特殊屬性
	 * @param builder
	 * @throws Exception
	 */
	void init(B builder) throws Exception;

	/**
	 * 設置SecurityBuilder<O>的特殊屬性
     * 如
	 */
	void configure(B builder) throws Exception;
}

SecurityConfigurer<O,B extends SecurityBuilder<O>>的實現類見下圖,終於見到了我們的老朋友WebSecurityConfigurerAdapter

                                         

WebSecurityConfigurer是繼承了SecurityConfigurer的接口,SecurityBuilder返回類型是Filter!!!

public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends
		SecurityConfigurer<Filter, T> {

}

WebSecurityConfigurerAdapter

對應的SecurityBuilder是WebSecurity(繼承SecurityBuilder<Filter>),裏面有方法init(WebSecurity web)和configure(WebSecurity Web)。三大configure()還記得麼?

configure(AuthenticationManagerBuilder auth) 
configure(HttpSecurity http)
configure(WebSecurity web)

如果不記得的話可以移步到上一章進行查閱。今天主要探討下WebSecurityConfigurerAdapter作爲SecuityBuilder<Filter>和SecurityConfigurer<Filter,T>的功能。

SecurityConfigurer的繼承類自然需要init()和configure()。

其中init()的作用是獲取HttpSecurity,並將http作爲SecurityBuilder<? extends SecurityFilterChain> 存入webSecurity.SecurityFilterChainBuilders屬性中。httpSecurity包含configurers屬性(如ExceptionHandlingConfigurer、),通過http.csrf().and()來設置configurer,後期這些configurers進行configure時會將特定的filter加入到httpSecurity中。

下圖是ExceptionHandlingConfigurer中的configure()方法

@Override
	public void configure(H http) throws Exception {
		AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
		ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
				entryPoint, getRequestCache(http));
		if (accessDeniedHandler != null) {
			exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler);
		}
		exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
		http.addFilter(exceptionTranslationFilter);
	}

下圖是WebSecurityConfigurerAdapter中的部分源碼

 

 

 

@Order(100)
public abstract class WebSecurityConfigurerAdapter implements
		WebSecurityConfigurer<WebSecurity> {


/**
*  AbstractConfiguredSecurityBuilder(實現類有WebSecurity,HttpSecurity等)中的init()
*  會遍歷所有configurers,調用configure.init()方法,那麼WebSecurityConfigurerAdapter作爲
*  configure調用的init()方法就是下面的代碼
*  獲取HttpSecurity,存入webSecurity中
*/
public void init(final WebSecurity web) throws Exception {
		final HttpSecurity http = getHttp();
		web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
			public void run() {
				FilterSecurityInterceptor securityInterceptor = http
						.getSharedObject(FilterSecurityInterceptor.class);
				web.securityInterceptor(securityInterceptor);
			}
		});
	}



/**
* 獲取HttpSecurity實例,configure(http)後,http中的屬性configurers注入相應的configurer
* http.csrf()會將CsrfConfigurer<HttpSecurity>存入HttpSecurity.configurers中
* http.csrf().disable()從HttpSecurity.configurers中移除CsrfConfigurer
* 依次類推
*/
protected final HttpSecurity getHttp() throws Exception {
		if (http != null) {
			return http;
		}

		DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
				.postProcess(new DefaultAuthenticationEventPublisher());
		localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

		AuthenticationManager authenticationManager = authenticationManager();
		authenticationBuilder.parentAuthenticationManager(authenticationManager);
		Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();

		http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
				sharedObjects);
		if (!disableDefaults) {
			// @formatter:off
            // headers()等方法將configure apply()到了http的屬性configurers中,這裏默認會注入10個configurer
			http
				.csrf().and()
				.addFilter(new WebAsyncManagerIntegrationFilter())
				.exceptionHandling().and()
				.headers().and()
				.sessionManagement().and()
				.securityContext().and()
				.requestCache().and()
				.anonymous().and()
				.servletApi().and()
				.apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
				.logout();
			// @formatter:on
			ClassLoader classLoader = this.context.getClassLoader();
                // 默認是爲空
			List<AbstractHttpConfigurer> defaultHttpConfigurers =
					SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);

			for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
				http.apply(configurer);
			}
		}
        // this.configurer(http)  根據this的實現類選擇對應方法
		configure(http);
		return http;
	}
}

SecurityFilterChain

定義一個Filter Chain,包含一組Filters,且提供方法判斷與request的路由是否匹配,源碼如下。

public interface SecurityFilterChain {

	boolean matches(HttpServletRequest request);

	List<Filter> getFilters();
}

SecurityFilterChain常用於SecurityBuilder<? extends SecurityFilterChain>,作爲builder的返回類型,通過build()獲取到實例後,存入FilterChainProxy的屬性List<SecurityFilterChain> filterChains中,在FilterChainProxy.doFilterInternal()中執行getFilters(HttpServletRequest request),找出對應request的SecurityFilterChain並返回Filters。

繼承類爲DefaultSecurityFilterChain,有屬性RequestMatcher requestMatcher和List<Filter> filters

FilterChainProxy

非常重要的知識點!!!

filter chain代理,由Spring管理生命週期。

在Spring Security框架中,用戶想要訪問資源需要經過FilterChainProxy(本質上是個Filter)來過濾。

裏面包含一組SecuriyFilterChains,每個uri都對應一個SecurityFilterChain,即對應SecurityFilterChain中的Filters

核心代碼如下

// 繼承了Filter
public class FilterChainProxy extends GenericFilterBean {

    // 重要屬性,由WebSecurity中的performBuild()方法傳遞值過來
	private List<SecurityFilterChain> filterChains;

	private FilterChainValidator filterChainValidator = new NullFilterChainValidator();


	public FilterChainProxy() {
	}

	public FilterChainProxy(SecurityFilterChain chain) {
		this(Arrays.asList(chain));
	}

	public FilterChainProxy(List<SecurityFilterChain> filterChains) {
		this.filterChains = filterChains;
	}

	
	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);
                  // 跳轉到doFilterInternal方法
				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);
          // 根據request,SecurityFilterChains獲取符合路由規則的SecurityFilterChain,並提取出filters
		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;
		}
           // 虛擬filter chain,這是個內部類,模擬doFilter的動作
		VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
		vfc.doFilter(fwRequest, fwResponse);
	}

         // 返回第一個滿足路由規則的SecurityFilterChain
         private List<Filter> getFilters(HttpServletRequest request) {
		for (SecurityFilterChain chain : filterChains) {
			if (chain.matches(request)) {
				return chain.getFilters();
			}
		}

		return null;
	}
}

WebSecurity

重頭戲來了,前面介紹的所有知識點都是爲了給它鋪路,簡單概括就是

本質是SecurityBuilder<Filter>

有重要屬性List<SecurityBuilder<? extends SecurityFilterChains>> securityFilterChainsBuilder,默認值是由WebSecurityConfigurerApdapter中傳入的HttpSecurity。

繼承了抽象類AbstractConfiguredSecurityBuilder(Filter,WebSecurity),重寫抽象方法performBuild(),創建FilterChainProxy(Filter的實現類)並返回

ignoring()方法排除無需認證的路徑

public final class WebSecurity extends
		AbstractConfiguredSecurityBuilder<Filter, WebSecurity> 
implements
		SecurityBuilder<Filter>, ApplicationContextAware {
private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<SecurityBuilder<? extends SecurityFilterChain>>();

    
/**
*   添加securityFilterChainBuilder
*   默認WebSecurityConfigurerAdapter中的init(WebSecurity web)方法會調用這個方法
*   傳入的securityFilterChainBuilder是getHttp()返回的HttpSecurity
*   securityFilterChainBuilder 是SecurityBuilder.build()返回SecurityFilterChain
*   SecurityFilterChain 有getFilters()和matches()方法
*/
public WebSecurity addSecurityFilterChainBuilder(
			SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
		this.securityFilterChainBuilders.add(securityFilterChainBuilder);
		return this;
}  


     /**
     * 返回類型是FilterChainProxy
     * 從securityFilterChainBuilders中遍歷securityFilterChainBuilder,將build()的返回值SecurityFilterChain寫入集合securityFilterChains中
     * 將securityFilterChains注入到新建的FilterChainProxy裏,FilterChainProxy.doFilterInternal()方法會從securityFilterChains中
     * 選取與request匹配的SecurityFilterChain,提取其中的filters作爲filter chain
     */
    @Override
	protected Filter performBuild() throws Exception {
		
		int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
		List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
				chainSize);
		for (RequestMatcher ignoredRequest : ignoredRequests) {
			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
			securityFilterChains.add(securityFilterChainBuilder.build());
		}
          // 傳入securityFilterChains初始化filterChainProxy,主要方法doFilterInternal()
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		if (httpFirewall != null) {
			filterChainProxy.setFirewall(httpFirewall);
		}
		filterChainProxy.afterPropertiesSet();

		Filter result = filterChainProxy;
		
		postBuildAction.run();
		return result;
	}
}

HttpSecurity

本質是SecurityBuilder<DefaultSecurityFilterChain>,可以傳入到WebSecurity的securityFilterChainBuilders屬性中

屬性 List<Filter> filters     方法  addFilter(),addFilterAt()等

一般在WebSecurityConfigurerApdater的繼承類中使用

@Configuration
	   @EnableWebSecurity
	   public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter {
	  
	   	@Override
	   	protected void configure(HttpSecurity http) throws Exception {
	   		http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin();
	   	}
	  
	   	@Override
	   	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	   		auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
	   				.and().withUser("adminr").password("password").roles("ADMIN", "USER");
	   	}
	   }

WebSecurityConfiguration

主要作用是初始化WebSecurity,且創建名爲“springSecurityFilterChain”類型爲FilterChainProxy的過濾器。

核心方法有

  • setFilterChainProxySecurityConfigurer
  • springSecurityFilterChain()

setFilterChainProxySecurityConfigurer創建webSecurity,並通過apply(Configurer c)方法注入spring容器管理的所有WebSecurityConfigurer。

/**
* spring注入SecurityConfigurer<FilterChainProxy,WebSecurity>
* webSecurityConfigurers 默認爲3個,
*/
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
			ObjectPostProcessor<Object> objectPostProcessor,
			@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
			throws Exception {
                // 新建webSecurity,然後apply() configurers
		webSecurity = objectPostProcessor
				.postProcess(new WebSecurity(objectPostProcessor));
		
        ...
		
        // 
        for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
			webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}

根據@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") 定位到下圖所示的方法,從beanFactory裏獲取所有類型爲WebSecurityConfigurer的實例,這裏有3個,其中securityConfig是自己編寫繼承WebSecurityConfigurerAdapter的類。

springSecurityFilterChain()通過webSecurity.build()方法創建名爲"springSecurityFilterChain"的FilterChainProxy

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public Filter springSecurityFilterChain() throws Exception {
           // 先執行了setFilterChainProxySecurityConfigurer()方法,所以屬性webSecurityConfigurers有值
		boolean hasConfigurers = webSecurityConfigurers != null
				&& !webSecurityConfigurers.isEmpty();
		if (!hasConfigurers) {
			WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
					.postProcess(new WebSecurityConfigurerAdapter() {
					});
			webSecurity.apply(adapter);
		}
             // 核心方法,返回FilterChainProxy
		return webSecurity.build();
	}

webSecurity.build()會觸發AbstractConfiguredSecurityBuilder中的doBuild()方法,裏面關鍵方法有init(),configurer()和performBuild(),最終返回FilterChainProxy

現在webSecurity裏的屬性configurers有3個:

securityConfig  (用戶自定義類繼承WebSecurityConfigurerAdapter)

ignoredPathsWebSecurityConfigurerApdater

SpringBootWebSecurityConfiguration

    @Override
	protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;

			beforeInit();
             // 遍歷init(),其中WebSecurityConfigurerAdapter的init()方法獲取包含configurers的HttpSecurity實例,存入webSecurity中
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
            // 遍歷configure()
			configure();

			buildState = BuildState.BUILDING;
            //  執行WebSecurity的performBuild()方法,將SecurityFilterChainBuilders(即httpSecurity集合)遍歷執行build()方法
            //  此時http.build()會將http裏的configurers屬性轉換後寫入filters中
            //  獲得SecurityFilterChains,存入FilterChainProxy中並返回
			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

總結

如果你看了一遍發現什麼也沒記住,那麼恭喜你,你已經達到了道家中無我的境界了

張三丰教張無忌太極拳,問他記住了多少。無忌說只記住了一半,再問記住多少,無忌想了會說已經全忘了,張三丰滿意的笑了,現在你可以去會玄冥二老了。

上面講的很零散,但都是基本,現在我們按程序執行順序串着講一遍,看能記住多少。

1.WebSecurityConfiguration初始化WebSecurity,並傳入configurers(類型爲WebSecurityConfigurer.class)屬性,如WebSecurityConfigurerApdater繼承類,IgnoredPathsWebSecurityConfigurerAdapter,ApplicationWebSecurityConfigurerAdapter等。最後執行webSecurity.build()返回FilterChainProxy,取名爲"springSecurityFilterChain"。

2.webSecurity.build()方法會調用AbstractConfiguredSecurityBuilder.doBuild(),即遍歷webSecurity.configurers,執行init()和configure(),最後performBuild()返回FilterChainProxy

2.1.WebSecurityConfigurerApdater.init()方法,通過getHttp()方法獲得配置好的HttpSecurity,裏面包含了configurers(如HeadersConfigurer,SecurityContextConfigure,LogoutConfigurer等)。將HttpSecurity添加到webSecurity的屬性securityFilterChainBuilders集合裏,以後在webSecurity.performBuild()中會調用。

2.2.WebSecurityConfigurerApdater.configure(webSecurity)方法,默認爲空,繼承類中可重寫該方法

2.3.webSecurity.performBuild(),遍歷securityFilterChainBuilders(即httpSecurity集合),執行http.build()方法獲得DefaultSecurityFilterChain,存入新建的FilterChainProxy中並返回。其中http.build()方法會將http中的configures屬性轉換成filter添加到http.filters屬性中,再根據http.performBuild()方法new DefaultSecurityFilterChain(requestMatcher,filters)並返回。

3.至此webSecurity.build()返還了FilterChainProxy,作爲bean由spring管理,專門用於用戶驗證和資源授權。當用戶訪問uri時,FilterChainProxy執行doFilterInternal()方法,選擇合適的SecurityFilterChain,提取其中的List<Filter> filters作爲addtionalFilters依次執行。

3.1 UsernamePasswordAuthenticationFilter      providerManager.authenticate()    將authentication存入SecurityConext裏和session中

3.2 FilterSecurityInterceptor  驗證權限,成功則直接訪問資源,失敗則跳轉到ExceptionTranslationFilter,接着跳轉到登錄界面

 

至此,FilterChainProxy從創建到調用整個流程我們就講完了,記住多少就看個人造化了。下一章我們將着重介紹UsernamePasswordAuthenticationFilter是怎麼運作的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章