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)
{ logger.info("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 :
private enum BuildState { UNBUILT(0), INITIALIZING(1), CONFIGURING(2), BUILDING
(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; } }
The five states are UNBUILT,INITIALIZING,CONFIGURING,BUILDING as well as
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
AbstractConfiguredSecurityBuilder.

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 ~

Technology
©2019-2020 Toolsou All rights reserved,
1190 Reverses the substring between each pair of parentheses leetcodemysql Joint index details You don't know ——HarmonyOS Create data mysql Library process Character recognition technology of vehicle license plate based on Neural Network A guess number of small games , use JavaScript realization Talking about uni-app Page value transfer problem pytorch of ResNet18( Yes cifar10 The accuracy of data classification is achieved 94%)C++ Method of detecting memory leak One is called “ Asking for the train ” A small village Finally got the train