The process of springSecurity injecting springSecurityFilterChain

Article directory

    • doBuild()
      • init()
      • configure()
      • performBuild()
    • Secondary doBuild
      • secondary init
      • secondary configure()
      • Secondary performBuild()
    • Returns the first performBuild
    • Summarize:

The process of springSecurity injecting springSecurityFilterChain:

If there is no webSecurityConfigure in the memory and no securityFilterChain, then create a new Adapter object. Here, there is a webSecurityConfigure in the memory, and its source is the manually added configuration class, as follows:

// Then execute the code: securityFilterChains length is 0, do not enter the inside of the for loop
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {<!-- -->
    this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
    for (Filter filter : securityFilterChain. getFilters()) {<!-- -->
        if (filter instanceof FilterSecurityInterceptor) {<!-- -->
            this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
            break;
        }
    }
}
// The length of webSecurityCustomizers is also 0
for (WebSecurityCustomizer customizer : this. webSecurityCustomizers) {<!-- -->
    customizer. customize(this. webSecurity);
}
// Focus on executing the build method
return this. webSecurity. build();

Then enter:

Continue to the doBuild() method:

doBuild()

// Enter doBuild() in the AbstractConfiguredSecurityBuilder class
@Override
protected final O doBuild() throws Exception {<!-- -->
    synchronized (this.configurers) {<!-- -->
        this.buildState = BuildState.INITIALIZING;
        beforeInit();
        init();
        this.buildState = BuildState.CONFIGURING;
        beforeConfigure();
        configure();
        this.buildState = BuildState.BUILDING;
        O result = performBuild();
        this.buildState = BuildState.BUILT;
        return result;
    }
}

init()

private void init() throws Exception {<!-- -->
    Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
    // The length of configurers is 1, which is the previous custom configuration class object: SpringSecurityTest object
    for (SecurityConfigurer<O, B> configurer : configurers) {<!-- -->
        configurer.init((B) this);
    }
    // this.configurersAddedInInitializing length=0
    for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {<!-- -->
        configurer.init((B) this);
    }
}

Enter the init method in the for loop: the next step is to initialize HttpSecurity

// web.addSecurityFilterChainBuilder() Enter the WebSecurity class to execute the addSecurityFilterChainBuilder() method:
public WebSecurity addSecurityFilterChainBuilder(
    SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {<!-- -->
    this.securityFilterChainBuilders.add(securityFilterChainBuilder);
    return this;
}
// After execution is complete, in WebSecurity,
// List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders, length = 1;

Then enter configure() in duBuild;

configure()

private void configure() throws Exception {<!-- -->
    Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
     // The length of configurers is 1, which is the previous custom configuration class object: SpringSecurityTest object
    for (SecurityConfigurer<O, B> configurer : configurers) {<!-- -->
        configurer. configure((B) this);
    }
}

// will enter the custom configuration class
@Override
public void configure(WebSecurity web) throws Exception {<!-- -->
    super. configure(web);
}

After the execution is complete, execute performBuild();

performBuild()

Here securityFilterChainBuilders length = 1, which is added in the previous init() method. Then enter the build() method

@Override
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");
}

Enter the doBuild method again, and also execute the init(), configure(), and performBuild methods

Secondary doBuild

Secondary init

This time, when entering init and obtaining the configuration, 12 configurations were obtained, all of which are built in spring security.

// 0, 1, 3, 6, 10
// ExceptionHandlingConfigurer, HeadersConfigurer, SecurityConfigurerAdapter's init did not operate

Take a screenshot of some configuration initialization content, you can skip it first:

logoutConfigure, init content:

After addMapping, there is one more content

Remember Me:

Secondary configure()

12 configuration objects are also traversed during configure

Screenshot part configure content:

Secondary performBuild()

After the previous configure, there are 12 elements in the filters at this time, and they need to be added to the DefaultSecurityFilterChain object.

Finally, the DefaultSecurityFilterChain object is returned, and it is also returned as a result in doBuild, and returns all the time, returning to the first performBuild

Return to the first performBuild

// part of performBuild():
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {<!-- -->
    // Add the DefaultSecurityFilterChain object returned earlier to securityFilterChains (a list object)
    securityFilterChains.add(securityFilterChainBuilder.build());
}
// Proxy securityFilterChains (length 1) to generate proxy object filterChainProxy
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
...
Filter result = filterChainProxy;
if (this.debugEnabled) {<!-- -->
    this.logger.warn("\
\
" + "************************************ ***********************************\
"
                      + "********** Security debugging is enabled. ***************\
"
                      + "********** This may include sensitive information. ***************\
"
                      + "********** Do not use in a production system! ***************\
"
                      + "************************************************ *********************\
\
");
    result = new DebugFilter(filterChainProxy);
}
// See below for details
this.postBuildAction.run();
// Finally return filterChainProxy
return result;
// this.postBuildAction.run();
// When the WebSecurityConfigurerAdapter called the init method earlier:
@Override
public void init(WebSecurity web) throws Exception {<!-- -->
    HttpSecurity http = getHttp();
    // There is a postBuildAction method here,
    web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {<!-- -->
        // When this.postBuildAction.run(); is executed, this method will be called:
        FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
        web.securityInterceptor(securityInterceptor);
    });
}

So add FilterSecurityInterceptor at the end

The first performBuilder will return FilterChainProxy and return to the springSecurityFilterChain() method return this.webSecurity.build();
The returned object is injected into Spring:

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
// where public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";

end

Summary:

? The injected springSecurityFilterChain object is generated by webSecurity.build();
? When building, first read the custom configuration, perform init, configure, and performBuild. During performBuild, it will load the configuration packaged by Springboot, then traverse, execute the init, configure, and performBuild methods respectively, and finally generate the chain from the loaded filters , and then proxy. Inject last.