Originally wanted to write about spring security source to read the article, but a matter of time considering the one hand, on the other hand, for practical purposes, there is going to start recording at the relevant loading process, request authentication and authorization processes.
Summarized as follows:
1. Start Process Overview
2, token acquisition process analysis
3, requested authentication and authorization process analysis
First, start the process overview
The main focus of the boot process involves loading configuration information and build a filter chain .
spring security framework is the core of the filter chain! It is the focus of the analysis process start and end debugging code to be concerned about.
First Viewpoint inlet class org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration, methods setFilterChainProxySecurityConfigurer there
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) { webSecurity.apply(webSecurityConfigurer); }
Configuration will org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter type (security-related), org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter type configuration (server resources), org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter type configuration (associated authorization server) are fitted into org.springframework.security.config.annotation.web.builders.WebSecurity object.
Stay tuned method springSecurityFilterChain ,
1 public Filter springSecurityFilterChain() throws Exception { 2 boolean hasConfigurers = webSecurityConfigurers != null 3 && !webSecurityConfigurers.isEmpty(); 4 if (!hasConfigurers) { 5 WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor 6 .postProcess(new WebSecurityConfigurerAdapter() { 7 }); 8 webSecurity.apply(adapter); 9 } 10 return webSecurity.build(); 11 }
Follow up on line 10, enter org.springframework.security.config.annotation.AbstractSecurityBuilder # build,
1 public final O build() throws Exception { 2 if (this.building.compareAndSet(false, true)) { 3 this.object = doBuild(); 4 return this.object; 5 } 6 throw new AlreadyBuiltException("This object has already been built"); 7 }
Continues into doBuild () method,
1 protected final O doBuild() throws Exception { 2 synchronized (configurers) { 3 buildState = BuildState.INITIALIZING; 4 5 beforeInit(); 6 init(); 7 8 buildState = BuildState.CONFIGURING; 9 10 beforeConfigure(); 11 configure(); 12 13 buildState = BuildState.BUILDING; 14 15 O result = performBuild(); 16 17 buildState = BuildState.BUILT; 18 19 return result; 20 } 21 }
Since spring security configuration are generally inherited org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter, look here for it. Key see above Line 6 init (), line 11 configure (), line 15 performBuild (). init () method will trigger org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter # init method,
1 public void init(final WebSecurity web) throws Exception { 2 final HttpSecurity http = getHttp(); 3 web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() { 4 public void run() { 5 FilterSecurityInterceptor securityInterceptor = http 6 .getSharedObject(FilterSecurityInterceptor.class); 7 web.securityInterceptor(securityInterceptor); 8 } 9 }); 10 }
Then look getHttp () method, the following code will be constructed which contains the default filter chain,
1 http 2 .csrf().and() 3 .addFilter(new WebAsyncManagerIntegrationFilter()) 4 .exceptionHandling().and() 5 .headers().and() 6 .sessionManagement().and() 7 .securityContext().and() 8 .requestCache().and() 9 .anonymous().and() 10 .servletApi().and() 11 .apply(new DefaultLoginPageConfigurer<>()).and() 12 .logout();
Each step corresponds to see out of the filter constructed by debug, as shown below:
Meanwhile getHttp () method finally there
1 configure(http)
Here performs org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter type of configuration (security-related), org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter type configuration (server resources) , org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter configure many types of configuration methods (authorization server-related).
This generally explains the creation and loading default filter chain processes the configuration information.
Two, token acquisition process analysis
This article is the use of password authentication mode oauth2 (Password Grant Type), in short, when you first authenticate the user passes username and password, authentication server returns a token, take this token later when a user requests access to a resource, you can access its privileged resources. Details Reference: https://developer.okta.com/blog/2018/06/29/what-is-the-oauth2-password-grant .
Therefore, this article refers to single sign-on process is to get the token of.
token is acquired links: / oauth / token, the corresponding code org.springframework.security.oauth2.provider.endpoint.TokenEndpoint # postAccessToken spring-security-oauth2 jar package;
To learn the entire flow through the filter, the filter can break track to perform the filter chain in the org.springframework.security.web.FilterChainProxy, specifically in org.springframework.security.web.FilterChainProxy.VirtualFilterChain #doFilter breakpoint in the method .
Here I mainly want to know the generated token, it is the breakpoint directly, go step by step in postAccessToken method until the following line of code,
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
Here is where the request is granted token, step by step to break with the inside, and finally back to the method org.springframework.security.oauth2.provider.CompositeTokenGranter # grant,
1 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) { 2 for (TokenGranter granter : tokenGranters) { 3 OAuth2AccessToken grant = granter.grant(grantType, tokenRequest); 4 if (grant!=null) { 5 return grant; 6 } 7 } 8 return null; 9 }
FIG tokenRequest herein below,
Literally see probably see five kinds of grant types that correspond oauth2 of grant types reference https://oauth.net/2/grant-types/ , we Granter password mode corresponds to the last figure above, the method org.springframework the third line different granter .security.oauth2.provider.CompositeTokenGranter # grant is based on grant type to select the appropriate granter, if not directly match return null. The method proceeds to a final grant Granter below,
protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) { return tokenServices.createAccessToken(getOAuth2Authentication(client, tokenRequest)); }
Finally into getOAuth2Authentication (client, tokenRequest), the method has the following code,
userAuth = authenticationManager.authenticate(userAuth);
AuthenticationManager above is a org.springframework.security.authentication.ProviderManager, encapsulates several org.springframework.security.authentication.AuthenticationProvider, provider authentication and returns a non-null Authentication is finished continue certification, we used in the project is org.springframework. security.authentication.dao.DaoAuthenticationProvider, she would do all kinds of check (for example configuration file is the Checker), user password verification, etc.;
接着进入org.springframework.security.oauth2.provider.token.DefaultTokenServices#createAccessToken(org.springframework.security.oauth2.provider.OAuth2Authentication)方法,
1 @Transactional 2 public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException { 3 4 OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication); 5 OAuth2RefreshToken refreshToken = null; 6 if (existingAccessToken != null) { 7 if (existingAccessToken.isExpired()) { 8 if (existingAccessToken.getRefreshToken() != null) { 9 refreshToken = existingAccessToken.getRefreshToken(); 10 // The token store could remove the refresh token when the 11 // access token is removed, but we want to 12 // be sure... 13 tokenStore.removeRefreshToken(refreshToken); 14 } 15 tokenStore.removeAccessToken(existingAccessToken); 16 } 17 else { 18 // Re-store the access token in case the authentication has changed 19 tokenStore.storeAccessToken(existingAccessToken, authentication); 20 return existingAccessToken; 21 } 22 } 23 24 // Only create a new refresh token if there wasn't an existing one 25 // associated with an expired access token. 26 // Clients might be holding existing refresh tokens, so we re-use it in 27 // the case that the old access token 28 // expired. 29 if (refreshToken == null) { 30 refreshToken = createRefreshToken(authentication); 31 } 32 // But the refresh token itself might need to be re-issued if it has 33 // expired. 34 else if (refreshToken instanceof ExpiringOAuth2RefreshToken) { 35 ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken; 36 if (System.currentTimeMillis() > expiring.getExpiration().getTime()) { 37 refreshToken = createRefreshToken(authentication); 38 } 39 } 40 41 OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken); 42 tokenStore.storeAccessToken(accessToken, authentication); 43 // In case it was modified 44 refreshToken = accessToken.getRefreshToken(); 45 if (refreshToken != null) { 46 tokenStore.storeRefreshToken(refreshToken, authentication); 47 } 48 return accessToken; 49 50 }
Our project uses redis storage token, if there is not expired token, return 20 rows directly behind the code is on refreshToken has expired, expired refresh process accessToken and refreshToken created, the default is UUID.randomUUID (). ToString () generates a UUID, the time has expired mechanisms, and finally deposit
tokenStore, for our project tokenStore is redis.
This token acquisition process analysis is completed.
Third, requested authentication and authorization process analysis
when the client application requests a child, you need to go first to an authentication server authentication, authorization server to detect and then to authority, how to do it? Suppose for the service application A, here two service authentication and authorization is done in one of, let's call it B;
authentication and authorization process diagram is as follows,