1、从Spring容器中获取WebSecurityConfigurerAdapter实例

  1. public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
  2. List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
  3. Map<String, WebSecurityConfigurer> beansOfType = beanFactory
  4. .getBeansOfType(WebSecurityConfigurer.class);
  5. for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
  6. webSecurityConfigurers.add(entry.getValue());
  7. }
  8. return webSecurityConfigurers;
  9. }

Spring容器中获取WebSecurityConfigurer的实例,即WebSecurityConfigurerAdapter。一般实际项目中我们都会去继承该类,虽然平时我们只写了一个SecurityConfig类去继承,但是允许自定义多个SecurityConfig继承自WebSecurityConfigurerAdapter,那么获取到的WebSecurityConfigurerAdapter实例也将有多个,即将来构建成功后会有多条过滤器链。
image.png

2、创建WebSecurity并且赋予配置类

  1. @Autowired(required = false)
  2. public void setFilterChainProxySecurityConfigurer(
  3. ObjectPostProcessor<Object> objectPostProcessor,
  4. @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
  5. throws Exception {
  6. webSecurity = objectPostProcessor
  7. .postProcess(new WebSecurity(objectPostProcessor));
  8. if (debugEnabled != null) {
  9. webSecurity.debug(debugEnabled);
  10. }
  11. webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
  12. Integer previousOrder = null;
  13. Object previousConfig = null;
  14. for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
  15. Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
  16. if (previousOrder != null && previousOrder.equals(order)) {
  17. throw new IllegalStateException(
  18. "@Order on WebSecurityConfigurers must be unique. Order of "
  19. + order + " was already used on " + previousConfig + ", so it cannot be used on "
  20. + config + " too.");
  21. }
  22. previousOrder = order;
  23. previousConfig = config;
  24. }
  25. for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
  26. webSecurity.apply(webSecurityConfigurer);
  27. }
  28. this.webSecurityConfigurers = webSecurityConfigurers;
  29. }

new一个WebSecurity对象,然后注入到Spring容器中。对上面获取到的WebSecurityConfigurerAdapter实例按照优先级进行排序,如果优先级相同,则会抛出异常,然后将上面排好序的WebSecurityConfigurerAdapter实例存入到WebSecurity对象中的configurers属性中。
image.png

3、使用WebSecurity构建FilterChainProxy

  1. @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
  2. public Filter springSecurityFilterChain() throws Exception {
  3. boolean hasConfigurers = webSecurityConfigurers != null
  4. && !webSecurityConfigurers.isEmpty();
  5. if (!hasConfigurers) {
  6. WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
  7. .postProcess(new WebSecurityConfigurerAdapter() {
  8. });
  9. webSecurity.apply(adapter);
  10. }
  11. return webSecurity.build();
  12. }

在上面创建完成WebSecurity对象之后,就开始执行WebSecuritybuild方法创建FilterChainProxy

4、WebSecurity构建FilterChainProxy过程

Spring Security过滤器架构(源码篇)一文中可以知道FilterChainProxy管理着多个过滤器链,那么,这些过滤器链是怎么构建出来的呢?带着疑问继续打断点执行下去。
上面已经执行到了WebSecurity对象的build方法,最后会来到其父类AbstractConfiguredSecurityBuilder中的doBuild方法:

  1. @Override
  2. protected final O doBuild() throws Exception {
  3. synchronized (this.configurers) {
  4. this.buildState = BuildState.INITIALIZING;
  5. beforeInit();
  6. init();
  7. this.buildState = BuildState.CONFIGURING;
  8. beforeConfigure();
  9. configure();
  10. this.buildState = BuildState.BUILDING;
  11. O result = performBuild();
  12. this.buildState = BuildState.BUILT;
  13. return result;
  14. }
  15. }

深入理解WebSecurityConfigurerAdapter(源码篇)一文中可以知道详细的方法就三个,initconfigureperformBuild方法。

4.1、init方法

  1. private void init() throws Exception {
  2. Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
  3. for (SecurityConfigurer<O, B> configurer : configurers) {
  4. configurer.init((B) this);
  5. }
  6. for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
  7. configurer.init((B) this);
  8. }
  9. }

第二步的时候已经将WebSecurityConfigurerAdapter实例集合,即我们自定义的SecurityConfig集合放到了WebSecurityconfigurers属性中,在此处就好用上了。依次执行每个configurerinit方法,init方法干了啥呢?

  1. @Override
  2. public void init(WebSecurity web) throws Exception {
  3. HttpSecurity http = getHttp();
  4. web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
  5. FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
  6. web.securityInterceptor(securityInterceptor);
  7. });
  8. }

4.1.1、调用getHttp创建HttpSecurity对象

让我们目光移到getHttp方法上:

  1. protected final HttpSecurity getHttp() throws Exception {
  2. if (this.http != null) {
  3. return this.http;
  4. }
  5. AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
  6. this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
  7. AuthenticationManager authenticationManager = authenticationManager();
  8. this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
  9. Map<Class<?>, Object> sharedObjects = createSharedObjects();
  10. this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
  11. if (!this.disableDefaults) {
  12. applyDefaultConfiguration(this.http);
  13. ClassLoader classLoader = this.context.getClassLoader();
  14. List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
  15. .loadFactories(AbstractHttpConfigurer.class, classLoader);
  16. for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
  17. this.http.apply(configurer);
  18. }
  19. }
  20. configure(this.http);
  21. return this.http;
  22. }

4.1.1.1、创建全局AuthenticationManager作为AuthenticationBuilder的父AuthenticationManager

getHttp方法中调用authenticationManager方法,在深入理解AuthenticationManagerBuilder(源码篇)一文中已经介绍过,该方法是用来创建全局AuthenticationManager

  1. protected AuthenticationManager authenticationManager() throws Exception {
  2. if (!this.authenticationManagerInitialized) {
  3. configure(this.localConfigureAuthenticationBldr);
  4. if (this.disableLocalConfigureAuthenticationBldr) {
  5. this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
  6. }
  7. else {
  8. this.authenticationManager = this.localConfigureAuthenticationBldr.build();
  9. }
  10. this.authenticationManagerInitialized = true;
  11. }
  12. return this.authenticationManager;
  13. }

在此方法中,先调用configure方法:

  1. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  2. this.disableLocalConfigureAuthenticationBldr = true;
  3. }

有没有觉得这个方法很熟悉,该方法就是我们在自定义配置类SecurityConfig继承自WebSeucrityConfigAdapter时会经常会重写的方法,如:

  1. @Override
  2. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  3. auth.userDetailsService(sysUserService).passwordEncoder(passwordEncoder());
  4. }

使用auth.userDetailsService(sysUserService)配置时,AuthenticationManagerBuilder会创建一个DaoAuthenticationConfigurer,添加到AuthenticationManagerBuilderconfigurers属性中,在后面AuthenticationManagerBuilder构建时会用到。
当我们重写WebSeucrityConfigAdapter#configure之后,上面的disableLocalConfigureAuthenticationBldr属性为false,就会使用我们配置的AuthenticationManagerBuilder来构建AuthenticationManager对象;当我们没有重写WebSeucrityConfigAdapter#configure时,disableLocalConfigureAuthenticationBldr属性变成true,然后就会使用自动注入的authenticationConfiguration中的getAuthenticationManager方法构建AuthenticationManager对象。

4.1.1.1.1、使用自己配置的AuthenticationManagerBuilder构建AuthenticationManager对象

最后会来到其父类AbstractConfiguredSecurityBuilder中的doBuild方法,然后又会依次执行initconfigureperformBuild方法。从上面可以知道只有一个DaoAuthenticationConfigurer配置类被添加到AuthenticationManagerBuilderconfigurers属性中,所以initconfigure就变成了DaoAuthenticationConfigurer去执行initconfigure方法。

4.1.1.1.1.1、DaoAuthenticationConfigurer执行init方法

追踪源码,发现该类以及父类都没有实现该方法,所以是空方法。

4.1.1.1.1.2、DaoAuthenticationConfigurer执行configure方法
  1. @Override
  2. public void configure(B builder) throws Exception {
  3. this.provider = postProcess(this.provider);
  4. builder.authenticationProvider(this.provider);
  5. }

在其父类AbstractDaoAuthenticationConfigurer中被实现,将当前配置好的DaoAuthenticationProvider对象添加到AuthenticationManagerBuilderauthenticationProviders属性中。

4.1.1.1.1.3、AuthenticationManagerBuilder执行performBuild方法
  1. @Override
  2. protected ProviderManager performBuild() throws Exception {
  3. if (!isConfigured()) {
  4. this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
  5. return null;
  6. }
  7. ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
  8. this.parentAuthenticationManager);
  9. if (this.eraseCredentials != null) {
  10. providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
  11. }
  12. if (this.eventPublisher != null) {
  13. providerManager.setAuthenticationEventPublisher(this.eventPublisher);
  14. }
  15. providerManager = postProcess(providerManager);
  16. return providerManager;
  17. }

new一个ProviderManager对象,传入authenticationProviders属性和parentAuthenticationManager属性。根据上面知道第一个参数其中存入了一个DaoAuthenticationProvider对象;因为当前是创建全局AuthenticationManager对象,所以并没有给该parentAuthenticationManager属性赋值。最后使用postProcessnew出来的ProviderManager对象放入Spring容器中,并且返回。

4.1.1.1.2、使用AuthenticationConfiguration中的getAuthenticationManager方法构建AuthenticationManager对象
  1. public AuthenticationManager getAuthenticationManager() throws Exception {
  2. if (this.authenticationManagerInitialized) {
  3. return this.authenticationManager;
  4. }
  5. AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
  6. if (this.buildingAuthenticationManager.getAndSet(true)) {
  7. return new AuthenticationManagerDelegator(authBuilder);
  8. }
  9. for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
  10. authBuilder.apply(config);
  11. }
  12. this.authenticationManager = authBuilder.build();
  13. if (this.authenticationManager == null) {
  14. this.authenticationManager = getAuthenticationManagerBean();
  15. }
  16. this.authenticationManagerInitialized = true;
  17. return this.authenticationManager;
  18. }

其中的构建过程和上面使用自己配置的AuthenticationManagerBuilder构建AuthenticationManager对象差不多,也是执行initconfigureperformBuild方法构建出一个AuthenticationManager对象并返回。

4.1.1.2、新建HttpSecurity对象

将上面构建好的全局AuthenticationManager对象放入局部authenticationBuilderparent属性中,然后在new``HttpSecurity对象的时候将局部authenticationBuilder当作参数传入进去,将其放到共享对象中,可以通过getAuthenticationRegistry方法获取出来。

  1. public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
  2. AuthenticationManagerBuilder authenticationBuilder, Map<Class<?>, Object> sharedObjects) {
  3. super(objectPostProcessor);
  4. Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
  5. setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
  6. for (Map.Entry<Class<?>, Object> entry : sharedObjects.entrySet()) {
  7. setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
  8. }
  9. ApplicationContext context = (ApplicationContext) sharedObjects.get(ApplicationContext.class);
  10. this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
  11. }

4.1.1.3、添加默认的配置类

  1. private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
  2. http.csrf();
  3. http.addFilter(new WebAsyncManagerIntegrationFilter());
  4. http.exceptionHandling();
  5. http.headers();
  6. http.sessionManagement();
  7. http.securityContext();
  8. http.requestCache();
  9. http.anonymous();
  10. http.servletApi();
  11. http.apply(new DefaultLoginPageConfigurer<>());
  12. http.logout();
  13. }

然后执行applyDefaultConfiguration方法,给上面new出来的HttpSecurity对象添加一系列默认的配置类而且还直接添加了一个WebAsyncManagerIntegrationFilter过滤器。默认的配置类有CsrfConfigurer``ExceptionHandlingConfigurer``HeadersConfigurer``SessionManagementConfigurer``SecurityContextConfigurer``RequestCacheConfigurer``AnonymousConfigurer``ServletApiConfigurer``DefaultLoginPageConfigurerLogoutConfigurer10个配置类。

4.1.1.4、执行configure(http)方法,进一步配置HttpSecurity对象

调用configure(http)方法,该方法是不是也很熟悉,我们一般在系统项目中的自定义配置类(继承自WebSecurityConfiguerAdapter)中,也会重写该方法。

  1. protected void configure(HttpSecurity http) throws Exception {
  2. this.logger.debug("Using default configure(HttpSecurity). "
  3. + "If subclassed this will potentially override subclass configure(HttpSecurity).");
  4. http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
  5. http.formLogin();
  6. http.httpBasic();
  7. }

默认的方法只是添加了FormLoginConfigurer``HttpBasicConfigurerExpressionUrlAuthorizationConfigurer三个配置类,并且指明了任何请求都必须认证。
如果重写该方法的话,则会按照我们项目需要添加或删除某些配置类,如:

  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3. http
  4. // 开启跨域访问
  5. .cors()
  6. .and()
  7. // 开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误
  8. .csrf()
  9. .disable()
  10. // 全局不创建session
  11. .sessionManagement()
  12. .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  13. .and()
  14. .formLogin()
  15. // 表单登录成功与失败处理器
  16. .failureHandler(authenticationFailureHandler)
  17. .successHandler(authenticationSuccessHandler)
  18. // 退出登录成功处理器
  19. .and()
  20. .logout()
  21. // 退出登录成功处理器
  22. .logoutSuccessHandler(logoutSuccessHandler)
  23. .and()
  24. .authorizeRequests()
  25. // 除了白名单之外的url都需要认证
  26. .antMatchers(SecurityConfigConstant.LOGIN_WHITE_URL)
  27. .permitAll()
  28. .anyRequest()
  29. .authenticated()
  30. // 异常处理器
  31. .and()
  32. .exceptionHandling()
  33. .authenticationEntryPoint(authenticationEntryPoint)
  34. .accessDeniedHandler(accessDeniedHandler)
  35. .and()
  36. // 禁用页面缓存,返回的都是json
  37. .headers()
  38. .frameOptions()
  39. .disable()
  40. .cacheControl();
  41. }

在上面重写的方法中,我们将csrf配置类给删除了,以及重新给部分其他原有的配置类进行了自定义配置,以后这里还可以根据项目需要添加额外的手机验证码登录或者第三方登录的配置类,全看自己需要,从这里就可以看出Spring Security的灵活以及强大之处。
最后,将配置好的HttpSecurity对象返回。

4.1.2、将HttpSecurity对象添加到securityFilterChainBuilders中

  1. public WebSecurity addSecurityFilterChainBuilder(
  2. SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
  3. this.securityFilterChainBuilders.add(securityFilterChainBuilder);
  4. return this;
  5. }

好了,至此WebSecurity对象的init方法执行完毕。
🎨总结一下:执行WebSecurity中的init方法,实际上是WebSecurity中的配置类集合Configurers循环执行每个Configurerinit方法,configurers集合中的数据来源于我们自定义了几个配置类继承自WebSecurityConfigurerAdapter,其中一个configurer执行完init方法之后就会将配置好的HttpSecurity对象添加到WebSecurity中的securityFilterChainBuilders集合中,在接下来的performBuild方法中会用到这个securityFilterChainBuilders集合,一个HttpSecurity构建出一条过滤器链。

4.2、configure方法

  1. private void configure() throws Exception {
  2. Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
  3. for (SecurityConfigurer<O, B> configurer : configurers) {
  4. configurer.configure((B) this);
  5. }
  6. }

WebSecurityConfigurerAdapter实例(即我们自定义的配置类-继承自WebSecurityConfigurerAdapter)集合中的每个Configurer依次执行configure方法。
好,我们来看看configure方法干了啥?

  1. @Override
  2. public void configure(WebSecurity web) throws Exception {
  3. }

别看是个空方法,但是不是很熟悉,在我们需要给某些前端页面的静态资源放行的时候,经常会在自定义配置类中重写该方法,这种方式放行的一个资源是单独生成一条过滤器链,都不会走认证授权那条过滤器链的。如:

  1. @Override
  2. public void configure(WebSecurity web) throws Exception {
  3. web.ignoring()
  4. .antMatchers("/swagger**/**")
  5. .antMatchers("/webjars/**")
  6. .antMatchers("/v3/**")
  7. .antMatchers("/doc.html");
  8. }
  1. public C antMatchers(String... antPatterns) {
  2. Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
  3. return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
  4. }
  1. @Override
  2. protected IgnoredRequestConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) {
  3. WebSecurity.this.ignoredRequests.addAll(requestMatchers);
  4. return this;
  5. }

上面这个方法会添加多个RequestMatchers放到WebSecurity对象中的ignoredRequests属性中。

4.3、PerformBuild方法

  1. protected Filter performBuild() throws Exception {
  2. Assert.state(!this.securityFilterChainBuilders.isEmpty(),
  3. () -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
  4. + "Typically this is done by exposing a SecurityFilterChain bean "
  5. + "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
  6. + "More advanced users can invoke " + WebSecurity.class.getSimpleName()
  7. + ".addSecurityFilterChainBuilder directly");
  8. int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
  9. List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
  10. List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
  11. for (RequestMatcher ignoredRequest : this.ignoredRequests) {
  12. WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
  13. + ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
  14. SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
  15. securityFilterChains.add(securityFilterChain);
  16. requestMatcherPrivilegeEvaluatorsEntries
  17. .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
  18. }
  19. for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
  20. SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
  21. securityFilterChains.add(securityFilterChain);
  22. requestMatcherPrivilegeEvaluatorsEntries
  23. .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
  24. }
  25. if (this.privilegeEvaluator == null) {
  26. this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
  27. requestMatcherPrivilegeEvaluatorsEntries);
  28. }
  29. FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
  30. if (this.httpFirewall != null) {
  31. filterChainProxy.setFirewall(this.httpFirewall);
  32. }
  33. if (this.requestRejectedHandler != null) {
  34. filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
  35. }
  36. filterChainProxy.afterPropertiesSet();
  37. Filter result = filterChainProxy;
  38. if (this.debugEnabled) {
  39. this.logger.warn("\n\n" + "********************************************************************\n"
  40. + "********** Security debugging is enabled. *************\n"
  41. + "********** This may include sensitive information. *************\n"
  42. + "********** Do not use in a production system! *************\n"
  43. + "********************************************************************\n\n");
  44. result = new DebugFilter(filterChainProxy);
  45. }
  46. this.postBuildAction.run();
  47. return result;
  48. }

4.3.1、断言

先断言securityFilterChainBuilders集合是否为空,为空的话直接报错!然后新建一个过滤器链集合securityFilterChains,集合的初始容量是ignoredRequests集合和securityFilterChainBuilders集合数量之和。

4.3.2、遍历ignoredRequests集合生成多个过滤器链

循环遍历ignoredRequests集合,这个集合中的数据在上面configure方法执行完后就已经被填充。一个放行资源会生成一条过滤器链,然后添加到securityFilterChains过滤器链集合。
image.png

4.3.3、遍历securityFilterChainBuilders集合生成多个过滤器链

接着开始循环遍历securityFilterChainBuilders集合,这个集合中的数据在上面init方法执行完后就会把我们自定义后的HttpSecurity添加到该集合中。遍历该集合,让该集合中的每一项去执行build方法,即让HttpSecurity对象去执行build方法,然后返回一条过滤器链添加到securityFilterChains过滤器链集合中。
那么HttpSecurity对象是怎么构建出一条过滤器链出来的呢?让我们继续跟踪源码!发现HttpSecurity执行build方法的时候又来到了我们最熟悉的AbstractConfiguredSecurityBuilder#dobuild方法,然后又是老三样,开始执行init``configureperformBuild方法,外加上beforeConfigure方法。

4.3.3.1、init方法

还是和以前一样,循环遍历configurers集合,执行每个xxxConfigurerinit方法。在前面WebSecurity对象执行init时就已经将默认的配置类和自定义的配置类(重写WebSecurityConfigurerAdapter#config(http)方法)放到了该集合中。
image.png
configurers集合中的xxxConfigurer就不一一分析了,就以FormLoginConfigurer为例,看看它执行init方法时干了啥?

  1. @Override
  2. public void init(H http) throws Exception {
  3. super.init(http);
  4. initDefaultLoginFilter(http);
  5. }
  1. @Override
  2. public void init(B http) throws Exception {
  3. updateAuthenticationDefaults();
  4. updateAccessDefaults(http);
  5. registerDefaultAuthenticationEntryPoint(http);
  6. }

先执行了父类AbstractAuthenticationFilterConfigurer中的init方法。

  1. 给当前的UsernamePasswordAuthenticationFilter过滤器配置默认的登录处理地址,失败跳转地址,注销成功跳转地址。
  2. 对登录页,登录处理地址和失败跳转地址放行。
  3. 注册异常处理器

然后再执行initDefaultLoginFilter方法,如果从当前的HttpSecurity中获取到默认登录页生成过滤器并且没有自定义登录页面,那么就重新配置默认登录页生成过滤器中的参数。

  1. private void initDefaultLoginFilter(H http) {
  2. DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
  3. .getSharedObject(DefaultLoginPageGeneratingFilter.class);
  4. if (loginPageGeneratingFilter != null && !isCustomLoginPage()) {
  5. loginPageGeneratingFilter.setFormLoginEnabled(true);
  6. loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
  7. loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter());
  8. loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
  9. loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
  10. loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
  11. }
  12. }

4.3.3.2、beforeConfigure方法

  1. @Override
  2. protected void beforeConfigure() throws Exception {
  3. if (this.authenticationManager != null) {
  4. setSharedObject(AuthenticationManager.class, this.authenticationManager);
  5. }
  6. else {
  7. setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
  8. }
  9. }
  10. private AuthenticationManagerBuilder getAuthenticationRegistry() {
  11. return getSharedObject(AuthenticationManagerBuilder.class);
  12. }

大家还记得在前面new``HttpSecurity的时候传入了一个AuthenticationManagerBuilder对象对吧,不记得可以在4.1.1.2章节处查看,使用获取出来的AuthenticationManagerBuilder对象执行build方法,不用多想,构建出来的对象就是ProviderManager对象,然后将ProviderManager存入共享对象中。

4.3.3.3、configure方法

还是和以前一样,循环遍历configurers集合,执行每个xxxConfigurerconfigure方法。以FormLoginConfigurer为例,看看它执行configure方法时干了啥?

  1. public void configure(B http) throws Exception {
  2. PortMapper portMapper = http.getSharedObject(PortMapper.class);
  3. if (portMapper != null) {
  4. this.authenticationEntryPoint.setPortMapper(portMapper);
  5. }
  6. RequestCache requestCache = http.getSharedObject(RequestCache.class);
  7. if (requestCache != null) {
  8. this.defaultSuccessHandler.setRequestCache(requestCache);
  9. }
  10. this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
  11. this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
  12. this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
  13. if (this.authenticationDetailsSource != null) {
  14. this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
  15. }
  16. SessionAuthenticationStrategy sessionAuthenticationStrategy = http
  17. .getSharedObject(SessionAuthenticationStrategy.class);
  18. if (sessionAuthenticationStrategy != null) {
  19. this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
  20. }
  21. RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
  22. if (rememberMeServices != null) {
  23. this.authFilter.setRememberMeServices(rememberMeServices);
  24. }
  25. F filter = postProcess(this.authFilter);
  26. http.addFilter(filter);
  27. }

它的configure在其父类中被实现。从HttpSecuriy的共享对象中取出AuthenticationManager对象,即我们在上一步存入进去的ProviderManager对象。然后重要的就是给该UsernamePasswordAuthenticationFilter设置认证成功处理器,认证失败处理器,记住我服务,然后注册到Spring容器,最后的最后就是将配置好的过滤器添加到HttpSecurity对象中。
至此,大家可以通过使用FormLoginConfigurer如何创建出UsernamePasswordAuthenticationFilter过滤器,来自己推导出HttpSecurity中其他xxxCofigurer是如何创建出其他过滤器的,这样一来,都将创建好的过滤器放入到HttpSecurity对象中的filters属性中。

4.3.3.4、performBuild方法

  1. @Override
  2. protected DefaultSecurityFilterChain performBuild() {
  3. this.filters.sort(OrderComparator.INSTANCE);
  4. List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
  5. for (Filter filter : this.filters) {
  6. sortedFilters.add(((OrderedFilter) filter).filter);
  7. }
  8. return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
  9. }

filters集合中的过滤器按照顺序排好,然后放入到新建的DefaultSecurityFilterChain过滤器链中,即一个过滤器链由多个过滤器组合而成,并返回。

4.3.4、生成FilterChainProxy

经过上面的步骤之后,会将生成的过滤器链全部添加到securityFilterChains集合中,在new``FilterChainProxy的时候将过滤器链集合securityFilterChains传入其中,这就和上面的一个FilterChainProxy管理着多个过滤器链不谋而合。给FilterChainProxy对象配置防火墙,并返回。