Let’s continue with the Spring Security source code.

SecurityConfigurer plays a very important role in Spring Security. As Songo has mentioned several times in previous articles, each filter in Spring Security’s filter chain is configured with xxxConfigurer, which is actually an implementation of SecurityConfigurer.

So it’s worth walking you through SecurityConfigurer today.

1. SecurityConfigurer

SecurityConfigurer is itself an interface. Let’s take a look:

public interface SecurityConfigurer<O.B extends SecurityBuilder<O>> {

	void init(B builder) throws Exception;

	void configure(B builder) throws Exception;
}
Copy the code

As you can see, there are two main methods in SecurityConfigurer, init and configure.

Init is an initialization method. Configure is a configuration method. Here only the definition of the method is standardized, the concrete implementation is in different implementation classes.

Note that both methods take a generic TYPE B, a subclass of SecurityBuilder, which is used to build filter chains, as Songo will describe in his next article.

SecurityConfigurer has three implementation classes:

  • SecurityConfigurerAdapter
  • GlobalAuthenticationConfigurerAdapter
  • WebSecurityConfigurer

Let’s look at them separately.

1.1 SecurityConfigurerAdapter

SecurityConfigurerAdapter implements SecurityConfigurer interface, we use the most xxxConfigurer are SecurityConfigurerAdapter subclass.

SecurityConfigurerAdapter on the basis of SecurityConfigurer and extended out several very good method, we look at:

public abstract class SecurityConfigurerAdapter<O.B extends SecurityBuilder<O>>
		implements SecurityConfigurer<O.B> {
	private B securityBuilder;

	private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();

	public void init(B builder) throws Exception {}public void configure(B builder) throws Exception {}public B and(a) {
		return getBuilder();
	}
	protected final B getBuilder(a) {
		if (securityBuilder == null) {
			throw new IllegalStateException("securityBuilder cannot be null");
		}
		return securityBuilder;
	}
	@SuppressWarnings("unchecked")
	protected <T> T postProcess(T object) {
		return (T) this.objectPostProcessor.postProcess(object);
	}
	public void addObjectPostProcessor(ObjectPostProcessor
        objectPostProcessor) {
		this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
	}
	public void setBuilder(B builder) {
		this.securityBuilder = builder;
	}
	private static final class CompositeObjectPostProcessor implements
			ObjectPostProcessor<Object> {
		privateList<ObjectPostProcessor<? >> postProcessors =new ArrayList<>();

		@SuppressWarnings({ "rawtypes"."unchecked" })
		public Object postProcess(Object object) {
			for(ObjectPostProcessor opp : postProcessors) { Class<? > oppClass = opp.getClass(); Class<? > oppType = GenericTypeResolver.resolveTypeArgument(oppClass, ObjectPostProcessor.class);if (oppType == null|| oppType.isAssignableFrom(object.getClass())) { object = opp.postProcess(object); }}return object;
		}
		private boolean addObjectPostProcessor( ObjectPostProcessor
        objectPostProcessor) {
			boolean result = this.postProcessors.add(objectPostProcessor);
			postProcessors.sort(AnnotationAwareOrderComparator.INSTANCE);
			returnresult; }}}Copy the code
  1. CompositeObjectPostProcessor first a CompositeObjectPostProcessor instance declaration at the beginning, CompositeObjectPostProcessor ObjectPostProcessor is an implementation, ObjectPostProcessor itself is a rear processor, the post processor default has two implementations, AutowireBeanFactoryObjectPostProcessor and CompositeObjectPostProcessor. Including AutowireBeanFactoryObjectPostProcessor mainly using the AutowireCapableBeanFactory to manually register, Bean, because in Spring Security, Many objects are new manually, and the new object doesn’t have anything to do with the container, using AutowireCapableBeanFactory these manual out new objects can be injected into the container, Whereas AutowireBeanFactoryObjectPostProcessor main role is to do it; CompositeObjectPostProcessor is a composite object processor, it maintains a set List, the List in the collection, in most cases only a data storage, That is AutowireBeanFactoryObjectPostProcessor, used to complete the object into the operation of the container, if the user manual call addObjectPostProcessor method, So CompositeObjectPostProcessor collection maintenance data will come out more than one, in CompositeObjectPostProcessor# postProcess method, It iterates through all objectPostProcessors in the collection, calling its postProcess method one by one to postProcess the objects.
  2. The and method returns a securityBuilder. SecurityBuilder is actually HttpSecurity. We can use the and method to chain configuration of different filters in HttpSecurity. This is because the and method is defined and the securityBuilder instance is returned.

This is the main function of SecurityConfigurerAdapter, behind most xxxConfigurer are based on such.

1.2 GlobalAuthenticationConfigurerAdapter

GlobalAuthenticationConfigurerAdapter see name will know that is a related to global configuration itself implements SecurityConfigurerAdapter interface, but not to do specific implementation methods, only the generic embodies:

@Order(100)
public abstract class GlobalAuthenticationConfigurerAdapter implements
		SecurityConfigurer<AuthenticationManager.AuthenticationManagerBuilder> {

	public void init(AuthenticationManagerBuilder auth) throws Exception {}public void configure(AuthenticationManagerBuilder auth) throws Exception {}}Copy the code

As you can see, the generic SecurityConfigurer, now became the AuthenticationManager and AuthenticationManagerBuilder definitely. So GlobalAuthenticationConfigurerAdapter implementation class is mainly related to configure the AuthenticationManager in the future. And of course the default username and password are configured by its implementation class.

The AuthenticationManager we use in Spring Security can actually be divided into two kinds, one is local, the other is global, here is the global configuration.

1.3 WebSecurityConfigurer

And an implementation class is WebSecurityConfigurer, this might have a friend is strange, actually he is WebSecurityConfigurerAdapter parent interface we use every day.

So the role of WebSecurityConfigurer is clear: the user extends the user-defined configuration.

SecurityConfigurer default is mainly the three implementation, considering that most of the filter configuration is extended by SecurityConfigurerAdapter, so today we are used to expand through the line. The other two lines will also be introduced by Songo in two articles.

2. SecurityConfigurerAdapter

SecurityConfigurerAdapter implementation is three broad categories:

  • UserDetailsAwareConfigurer
  • AbstractHttpConfigurer
  • LdapAuthenticationProviderConfigurer

Given how little LDAP is used today, I’d like to highlight the first two.

2.1 UserDetailsAwareConfigurer

This configuration class is used to configure the user class, as its name implies.

AbstractDaoAuthenticationConfigurer

AbstractDaoAuthenticationConfigurer do relatively simple, mainly constructs a default DaoAuthenticationProvider, PasswordEncoder and UserDetailsService are configured.

UserDetailsServiceConfigurer

The configure method of UserDetailsServiceConfigurer rewrite the AbstractDaoAuthenticationConfigurer, The initUserDetailsService method is added before the configure method is executed so that the developer can initialize the UserDetailsService in its own way. However, the initUserDetailsService method here is empty.

UserDetailsManagerConfigurer

Implement the UserDetailsServiceConfigurer UserDetailsManagerConfigurer defined initUserDetailsService method, The specific implementation logic is to store the UserDetails constructed by UserDetailsBuilder and the users in the prepared UserDetails to UserDetailsService.

This class also adds a withUser method to add users, and also adds a UserDetailsBuilder to build users. These logic are relatively simple, and you can view them by yourself.

JdbcUserDetailsManagerConfigurer

JdbcUserDetailsManagerConfigurer on the basis of the parent class adds a DataSource object, but also provides a corresponding database query method.

InMemoryUserDetailsManagerConfigurer

InMemoryUserDetailsManagerConfigurer on the basis of the parent class overrides the constructor, defined as InMemoryUserDetailsManager UserDetailsService from the parent class instance.

DaoAuthenticationConfigurer

DaoAuthenticationConfigurer inherited from AbstractDaoAuthenticationConfigurer, just a change in the way of constructing the userDetailsService.

A friend might ask, JdbcUserDetailsManagerConfigurer or InMemoryUserDetailsManagerConfigurer, exactly where I can use?

Songo gives you a simple example:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("javaboy")
                .password("{noop}123")
                .roles("admin");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                / / to omit}}Copy the code

When you call the auth. InMemoryAuthentication configured, is InMemoryUserDetailsManagerConfigurer actually call.

There you have it!

2.2 AbstractHttpConfigurer

There’s a whole class of AbstractHttpConfigurer, and all of our filter configurations are subclasses of that class. What are those classes?

As you can see, there are quite a few implementation classes.

FormLoginConfigurer (FormLoginConfigurer); FormLoginConfigurer (FormLoginConfigurer);

Let’s take it one by one.

2.2.1 AbstractHttpConfigurer

AbstractHttpConfigurer inherited from SecurityConfigurerAdapter, and increases the two methods, the disable and withObjectPostProcessor:

public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T.B>, B extends HttpSecurityBuilder<B>>
		extends SecurityConfigurerAdapter<DefaultSecurityFilterChain.B> {

	/**
	 * Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
	 * version of the configuration can be applied.
	 *
	 * @return the {@link HttpSecurityBuilder} for additional customizations
	 */
	@SuppressWarnings("unchecked")
	public B disable(a) {
		getBuilder().removeConfigurer(getClass());
		return getBuilder();
	}

	@SuppressWarnings("unchecked")
	public T withObjectPostProcessor(ObjectPostProcessor
        objectPostProcessor) {
		addObjectPostProcessor(objectPostProcessor);
		return (T) this; }}Copy the code

Disable () isa function of.csrf(). Disable () isa function of.csrf(). Remove xxxConfigurer from getBuilder. The getBuilder method actually gets HttpSecurity, so removing xxxConfigurer is actually removing a filter from the filter chain. For example.csrf().disable() removes the filter that processes the CSRF.

Another addition is withObjectPostProcessor, which manually adds a post-processor for configuration class additions. The Subclass AbstractHttpConfigurer has an analogous method called addObjectPostProcessor, but addObjectPostProcessor is an add-on method that returns void. The return value of withObjectPostProcessor is the current configuration class, which is xxxConfigurer, so if you use withObjectPostProcessor, you can use chained configuration. In fact, in a previous article by Songo, And the VHR (github.com/lenve/vhr) project, using the withObjectPostProcessor method (of course, you can also use addObjectPostProcessor, the end result is the same).

2.2.2 AbstractAuthenticationFilterConfigurer

AbstractAuthenticationFilterConfigurer class is more, the source code is quite long. There are only two methods to focus on, init and configure, because these are the soul of all xxxConfigurer methods.

@Override
public void init(B http) throws Exception {
	updateAuthenticationDefaults();
	updateAccessDefaults(http);
	registerDefaultAuthenticationEntryPoint(http);
}
Copy the code

The init method does three things:

  1. UpdateAuthenticationDefaults mainly is to configure the log processing address, jump address failure, cancellation of successful jump address.
  2. The updateAccessDefaults method performs permitAll Settings on loginPage, loginProcessingUrl, and failureUrl (if permitAll is configured).
  3. Abnormal registerDefaultAuthenticationEntryPoint is registered processor.

Let’s look at the configure method:

@Override
public void configure(B http) throws Exception {
	PortMapper portMapper = http.getSharedObject(PortMapper.class);
	if(portMapper ! =null) {
		authenticationEntryPoint.setPortMapper(portMapper);
	}
	RequestCache requestCache = http.getSharedObject(RequestCache.class);
	if(requestCache ! =null) {
		this.defaultSuccessHandler.setRequestCache(requestCache);
	}
	authFilter.setAuthenticationManager(http
			.getSharedObject(AuthenticationManager.class));
	authFilter.setAuthenticationSuccessHandler(successHandler);
	authFilter.setAuthenticationFailureHandler(failureHandler);
	if(authenticationDetailsSource ! =null) {
		authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
	}
	SessionAuthenticationStrategy sessionAuthenticationStrategy = http
			.getSharedObject(SessionAuthenticationStrategy.class);
	if(sessionAuthenticationStrategy ! =null) {
		authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
	}
	RememberMeServices rememberMeServices = http
			.getSharedObject(RememberMeServices.class);
	if(rememberMeServices ! =null) {
		authFilter.setRememberMeServices(rememberMeServices);
	}
	F filter = postProcess(authFilter);
	http.addFilter(filter);
}
Copy the code

The logic in configure is straightforward: build various callback functions to set up the authFilter, the authFilter goes through the postProcess to register with the Spring container, and finally adds the authFilter to the filter chain.

This is the main function of AbstractAuthenticationFilterConfigurer. We need to remind you that our daily configuration, such as:

  • loginPage
  • loginProcessingUrl
  • permitAll
  • defaultSuccessUrl
  • failureUrl
  • .

And so on are defined here.

Finally, let’s look at FormLoginConfigurer.

2.2.3 FormLoginConfigurer

FormLoginConfigurer in definition is, has been clear about the AbstractAuthenticationFilterConfigurer of generics are UsernamePasswordAuthenticationFilter, We are here to configure filter is UsernamePasswordAuthenticationFilter finally.

FormLoginConfigurer overrides the init method to configure the default login page. Everything else is basically from the parent class without much change.

In addition, many of our daily configurations also come from here:

Ok, this is FormLoginConfigurer the configuration class, FormLoginConfigurer corresponding filter is UsernamePasswordAuthenticationFilter, You can analyze other xxxConfigurer files by yourself. Each xxxConfigurer has a different Filter.

3. Summary

Well, today I’m going to share the source code for SecurityConfigurer, but there’s a lot more to discuss in detail, and Songo will continue to share it in a future article.

If you think you have something to gain, remember to click on the song Brother under the encouragement of watching