HttpSecurity So is it Spring Security An important link in . Most of what we usually do Spring Security Configuration is also based on
HttpSecurity To configure . Therefore, we need to understand from the perspective of source code HttpSecurity What did you do ?

<>1. reel silk from cocoons -- make a painstaking investigation

First of all, let's take a look HttpSecurity Inheritance diagram of :

You can see ,HttpSecurity Inherited from AbstractConfiguredSecurityBuilder, At the same time SecurityBuilder
and HttpSecurityBuilder Two interfaces .

Let's take a look HttpSecurity Definition of :
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<
DefaultSecurityFilterChain, HttpSecurity> implements SecurityBuilder<
DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> { //... }
Every class here has generics , It's a bit dazzled .

Let me show you this generic class , My friends will understand .

Generics are mainly two ,DefaultSecurityFilterChain and HttpSecurity,HttpSecurity
Needless to say , This is our main character today , that DefaultSecurityFilterChain What is it ?

So we have to start from SecurityFilterChain Yes .

<>1.1 SecurityFilterChain

Let's start with the definition :
public interface SecurityFilterChain { boolean matches(HttpServletRequest
request); List<Filter> getFilters(); }
SecurityFilterChain That's what we usually say Spring Security Filter chain in , It defines two methods , One is matches
Method is used to match the request , Another one getFilters Method returns a List aggregate , In the collection Filter object , When a request comes , use matches
Method to compare whether the request matches the current chain , If it fits , Just go back getFilters Filter in method , Then the current request will go through one by one List
Filters in the collection . this point , Friends can recall the front 【 In depth understanding FilterChainProxy【 Source code 】】 One article .

SecurityFilterChain Interface has only one implementation class , That's it DefaultSecurityFilterChain:
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.
class); private final RequestMatcher requestMatcher; private final List<Filter>
filters; public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter
... filters) { this(requestMatcher, Arrays.asList(filters)); } public
DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters)
{"Creating filter chain: " + requestMatcher + ", " + filters); this
.requestMatcher = requestMatcher; this.filters = new ArrayList<>(filters); }
public RequestMatcher getRequestMatcher() { return requestMatcher; } public List
<Filter> getFilters() { return filters; } public boolean matches(
HttpServletRequest request) { return requestMatcher.matches(request); }
@Override public String toString() { return "[ " + requestMatcher + ", " +
filters+ "]"; } }
DefaultSecurityFilterChain It's just right SecurityFilterChain
The method in is implemented , There is nothing special to say , SongGe is no longer wordy .

So from the introduction above , You can see ,DefaultSecurityFilterChain In fact, it is equivalent to Spring Security Filter chain in , One
DefaultSecurityFilterChain Represents a filter chain , If there are multiple filter chains in the system , There will be more than one
DefaultSecurityFilterChain object .

Next we put HttpSecurity Let's take a look .

<>1.2 SecurityBuilder
public interface SecurityBuilder<O> { O build() throws Exception; }
SecurityBuilder Is used to build the filter chain , stay HttpSecurity realization SecurityBuilder Time , The generic type passed in is
DefaultSecurityFilterChain, therefore SecurityBuilder#build The function of the method is very clear , It is used to build a filter chain .

<>1.3 HttpSecurityBuilder

HttpSecurityBuilder The name is used to build HttpSecurity Of . But it's just an interface , The concrete realization is in HttpSecurity
in , The interface is defined as follows :
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
SecurityBuilder<DefaultSecurityFilterChain> { <C extends SecurityConfigurer<
DefaultSecurityFilterChain, H>> C getConfigurer( Class<C> clazz); <C extends
SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer( Class<C>
clazz); <C> void setSharedObject(Class<C> sharedType, C object); <C> C
getSharedObject(Class<C> sharedType); H authenticationProvider(
AuthenticationProvider authenticationProvider); H userDetailsService(
UserDetailsService userDetailsService) throws Exception; H addFilterAfter(
Filter filter, Class<? extends Filter> afterFilter); H addFilterBefore(Filter
filter, Class<? extends Filter> beforeFilter); H addFilter(Filter filter); }
The method here is relatively simple :

* getConfigurer Gets a configuration object .Spring Security All filter objects in the filter chain are created by xxxConfigure
To configure , Here's how to get this xxxConfigure object .
* removeConfigurer Remove a configuration object .
* setSharedObject/getSharedObject to configure / Get by multiple SecurityConfigurer Shared objects .
* authenticationProvider Method represents the configuration validator .
* userDetailsService Configure data source interface .
* addFilterAfter Adding a filter before a filter .
* addFilterBefore Add a filter after a filter .
* addFilter Add a filter , The filter must be a filter in the existing filter chain or its extension .
That's it HttpSecurityBuilder Functions in , These interfaces are HttpSecurity Will be implemented .

<>1.4 AbstractSecurityBuilder

AbstractSecurityBuilder Class implements the SecurityBuilder Interface , There is one main thing that is done in this class , Is to make sure that the entire build is only built once .
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O>
{ private AtomicBoolean building = new AtomicBoolean(); private O 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"); } public final O getObject() { if (!this
.building.get()) { throw new IllegalStateException("This object has not been
built"); } return this.object; } protected abstract O doBuild() throws Exception
; }
You can see , It's redefined here build method , And set build The method is as follows final type , Cannot be overridden , stay build Method , adopt
AtomicBoolean The implementation of this method is called only once . The concrete construction logic defines a new abstract method doBuild, In the future, the doBuild Method definition build logic .

<>1.5 AbstractConfiguredSecurityBuilder

AbstractSecurityBuilder The implementation class of the method is AbstractConfiguredSecurityBuilder.

AbstractConfiguredSecurityBuilder There's more to be done , Let's look at it separately .

first AbstractConfiguredSecurityBuilder An enumeration class is defined in , The whole construction process is divided into 5
States , It can also be understood as the five phases of the construction process life cycle , as follows :
(3), BUILT(4); private final int order; BuildState(int order) { this.order =
order; } public boolean isInitializing() { return INITIALIZING.order == order; }
public boolean isConfigured() { return order >= CONFIGURING.order; } }
BUILT. In addition, two judgment methods are provided ,isInitializing Determine whether initialization is in progress ,isConfigured Indicates whether the configuration has been completed .

AbstractConfiguredSecurityBuilder There are many methods in , SongGe here listed two key methods and everyone's analysis :
private <C extends SecurityConfigurer<O, B>> void add(C configurer) { Assert.
notNull(configurer, "configurer cannot be null"); Class<? extends
SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>)
configurer.getClass(); synchronized (configurers) { 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<>(1); } configs.add(configurer); this.
configurers.put(clazz, configs); if (buildState.isInitializing()) { this.
configurersAddedInInitializing.add(configurer); } } } private Collection<
SecurityConfigurer<O, B>> getConfigurers() { List<SecurityConfigurer<O, B>>
result= new ArrayList<>(); for (List<SecurityConfigurer<O, B>> configs : this.
configurers.values()) { result.addAll(configs); } return result; }
The first one is this add method , This is equivalent to collecting all configuration classes . Will all xxxConfigure Collect and store in configurers
in , It will be initialized and configured in the future ,configurers Itself is a LinkedHashMap ,key Is the configuration class class,value
It's a collection , It's in the collection xxxConfigure Configuration class . When these configuration classes need to be configured centrally , Will pass getConfigurers
Method to get the configuration class , This acquisition process is to LinkedHashMap Medium value take out , Put it in a collection and return .

The other way is doBuild method .
@Override protected final O doBuild() throws Exception { synchronized (
configurers) { buildState = BuildState.INITIALIZING; beforeInit(); init();
buildState= BuildState.CONFIGURING; beforeConfigure(); configure(); buildState =
BuildState.BUILDING; O result = performBuild(); buildState = BuildState.BUILT;
return result; } } private void init() throws Exception { Collection<
SecurityConfigurer<O, B>> configurers = getConfigurers(); for (
SecurityConfigurer<O, B> configurer : configurers) { configurer.init((B) this);
} for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this); } } private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers(); for (
SecurityConfigurer<O, B> configurer : configurers) { configurer.configure((B)
this); } }
stay AbstractSecurityBuilder Class , The construction of the filter is transferred to doBuild The method is up , But in the
AbstractSecurityBuilder It just defines abstract doBuild method , The concrete realization is in

doBuild The way to do this is to update the status , To initialize .

beforeInit It's a reserved method , There is no implementation .

init The way is to find everything xxxConfigure, Call them one by one init Method .

beforeConfigure It's a reserved method , There is no implementation .

configure The way is to find everything xxxConfigure, Call them one by one configure Method to configure .

At the end of the day performBuild method , It's a real filter chain building method , But in the AbstractConfiguredSecurityBuilder in
performBuild Method is just an abstract method , The concrete realization is in HttpSecurity in .

That's it HttpSecurity All parent classes , Function of parent interface .

After watching my parents , Let's go back to the topic of today's article ,HttpSecurity.

<>2. HttpSecurity

HttpSecurity What to do , It's all kinds of activities xxxConfigurer to configure .

Just a few examples :
public CorsConfigurer<HttpSecurity> cors() throws Exception { return getOrApply
(new CorsConfigurer<>()); } public CsrfConfigurer<HttpSecurity> csrf() throws
Exception{ ApplicationContext context = getContext(); return getOrApply(new
CsrfConfigurer<>(context)); } public ExceptionHandlingConfigurer<HttpSecurity>
exceptionHandling() throws Exception { return getOrApply(new
ExceptionHandlingConfigurer<>()); }
HttpSecurity There are a number of similar methods in , The filters in the filter chain are configured one by one . I will not introduce them one by one .

There is a sentence at the end of each configuration method getOrApply, What's this for ?
private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,
HttpSecurity>> C getOrApply( C configurer) throws Exception { C existingConfig =
(C) getConfigurer(configurer.getClass()); if (existingConfig != null) { return
existingConfig; } return apply(configurer); }
getConfigurer Method is in its parent class AbstractConfiguredSecurityBuilder As defined in , The goal is to check the current one
xxxConfigurer Has it been configured .

If the current xxxConfigurer It's already configured , It will return directly , Otherwise, call apply method , this apply Method will eventually be called to the
AbstractConfiguredSecurityBuilder#add method , Set the current configuration configurer Collect them .

HttpSecurity There's another one in it addFilter method :
public HttpSecurity addFilter(Filter filter) { Class<? extends Filter>
filterClass= filter.getClass(); if (!comparator.isRegistered(filterClass)) {
throw new IllegalArgumentException( "The Filter class " + filterClass.getName()
+ " does not have a registered order and cannot be added without a specified
order. Consider using addFilterBefore or addFilterAfter instead."); } this.
filters.add(filter); return this; }
this addFilter The role of the method , Mainly in each xxxConfigurer When configuring , This method is called ,(xxxConfigurer
It is used to configure the filter ), hold Filter All added to fitlers Variable .

In the end HttpSecurity Of performBuild Method , Build a chain of filters :
@Override protected DefaultSecurityFilterChain performBuild() { filters.sort(
comparator); return new DefaultSecurityFilterChain(requestMatcher, filters); }
Sort the filters first , And then construct DefaultSecurityFilterChain object .

<>3. Summary

All right , This is it. HttpSecurity A general workflow of . Grasp the workflow , The rest is just a few simple repetitions xxxConfigurer
Configured , SongGe is no longer wordy .

If the partners feel there is something to gain , Remember to watch and encourage SongGe ~

©2019-2020 Toolsou All rights reserved,
Non preemptive static priority scheduling algorithm for operating system (C language )Go Language learning notes (GUI programming )XCTF Attack and defense world web Advanced practice _ 2_lottery What's the difference between computer major and training background ?python realization vlookup_ Dry goods I : Why python It's inside vlookup Bubble sort primary springboot2 Separation of front and rear platforms ,token Put in header Pit for verification Python Case conversion of letters ( Two methods )javascript event ( Detailed explanation of zero basis )Unity2019 UIElement note ( ten ) Simple exercise 2