preface

Text has been included to my lot warehouse, welcome Star:https://github.com/bin392328206/six-finger plant a tree is the best time ten years ago, followed by now

omg

Just met, let’s go through the process

This article describes the scope of the certification process

This article mainly explains several key points in the process from the user initiating the request to obtain the token (/oauth/token) to the end of the request to return the token.

Relevant requests to be used for authentication

Access_token Request (/oauth/token)

  • Parameters required for the request are client_id, client_secret, grant_type, username, and password
http://localhost/oauth/token?client_id=demoClientId&client_secret=demoClientSecret&grant_type=password&username=demoUser &password=50575tyL86xp29O380t1Copy the code

Check whether headers are valid requests (/oauth/check_token)

  • Parameter required for request: token
http://localhost/oauth/check_token?token=f57ce129-2d4d-4bd7-1111-f31ccc69d4d1
Copy the code

Refreshing token requests (/oauth/token)

Parameters required for the request: grant_type, refresh_token, client_id, and client_secret Grant_type is a fixed value: grant_type=refresh_token

http://localhost/oauth/token?grant_type=refresh_token&refresh_token=fbde81ee-f419-42b1-1234-9191f1f95be9&client_id=demoC lientId&client_secret=demoClientSecretCopy the code

The working principle of

Structure of the overview

The problem Spring Security addresses is secure access control, which essentially intercepts all incoming requests to verify that each request has access to the desired resource. We can realize it through Filter or AOP and other technologies. Spring Security’s protection of Web resources is realized by Filter, so start with this Filter and gradually deepen the principle of Spring Security.

When initializing Spring Security, will create a named SpringSecurityFilterChain Servlet filters, Type of org. Springframework. Security. Web. Named FilterChainProxy, it implements the javax.mail. Servlet. The Filter, so the external request will pass this class, here is Spring security screening device chain structure:

FilterChainProxy is a proxy. What really works is the filters contained in the SecurityFilterChain of FilterChainProxy. These filters are managed as beans by Spring. They are the core of Spring Security and have their own responsibilities, but they don’t directly deal with user authentication or user authorization, Instead, they are handed over to the AuthenticationManager and AccessDecisionManager for processing, as shown below in the UML diagram of the FilterChainProxy related classes.


The implementation of Spring Security features is primarily a chain of filters that work together.


The following are the main filters in the filter chain and their functions

  • SecurityContextPersistenceFilter this Filter is the entry and exit of the interception process (that is, the first and the last interceptor), Will get in at the beginning of the request from the configuration good SecurityContextRepository SecurityContext, then set it to SecurityContextHolder. At the completion of a request to hold SecurityContextHolder SecurityContext again saved to the configured SecurityContextRepository, Also clears the SecurityContext held by securityContextHolder;
  • UsernamePasswordAuthenticationFilter from the form is submitted for certification. The form must provide the corresponding user name and code, its internal and login for processing after the success or failure of AuthenticationSuccessHandler and AuthenticationFailureHandler, these can make relevant changes according to the requirements;
  • FilterSecurityInterceptor is used to protect a web resource, use the AccessDecisionManager to grant access to the current user, surface before a detailed introduction has been made.
  • ExceptionTranslationFilter capture from FilterChain all exceptions, and processing. But it only handles two types of exceptions: AuthenticationException and AccessDeniedException, and it continues to throw the others.

The certification process


Let’s take a closer look at the certification process:

    1. The user submits the user name and password are SecurityFilterChain UsernamePasswordAuthenticationFilter filter access to, encapsulation for requesting Authentication, Usually UsernamePasswordAuthenticationToken the implementation class.
    1. The filter then submits Authentication to the AuthenticationManager for Authentication
    1. After successful Authentication, the AuthenticationManager identity manager returns an Authentication instance filled with information (including the permission information, identity information, details mentioned above, but passwords are usually removed).
    1. SecurityContextHolder security context container will step 3 to fill the information Authentication, through SecurityContextHolder. GetContext () setAuthentication (…). Method is set to. It can be seen that the AuthenticationManager interface is the core interface related to authentication and also the starting point of initiating authentication. Its implementation class is ProviderManager. Spring Security supports multiple authentication methods, so the ProviderManager maintains a List of authentication methods, and the actual authentication is done by the AuthenticationProvider. Let’s know a web form corresponding AuthenticationProvider implementation class for the DaoAuthenticationProvider, its internal also maintains a UserDetailsService responsible for get populated UserDetails. Finally, the AuthenticationProvider populates the UserDetails into Authentication. The general relationship between the authentication core components is as follows:

AuthenticationProvider

From the previous Spring Security authentication process, we learned that the AuthenticationManager (AuthenticationManager) entrusts the AuthenticationProvider to do the authentication. AuthenticationProvider is an interface defined as follows

public interface AuthenticationProvider { Authentication authenticate(Authentication authentication) throws AuthenticationException; boolean supports(Class<? > var1); }Copy the code

The authenticate() method defines the Authentication process. Its parameter is Authentication, which contains the user and password submitted by the login user. The return value is also an Authentication, which is generated after the user’s permissions and other information are reassembled after the Authentication is successful.

Spring Security maintains a List of various authentication modes. Different authentication modes use different AuthenticationProvider. There are many examples, such as using AuthenticationProvider1 for login with username and password, AuthenticationProvider2 for SMS login, and so on.

Each AuthenticationProvider needs to implement the supports () method to indicate the authentication mode it supports. If we use form authentication, Spring Security will generate UsernamePasswordAuthenticationToken when submit a request, it is an Authentication, encapsulated inside a user submits a user name and password information. And which AuthenticationProvider handles it?

We found in the base class for DaoAuthenticationProvider AbstractUserDetailsAuthenticationProvider the following code:

public boolean supports(Class<? > authentication) {return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); }
Copy the code

That is when the web form submission usernames and passwords, Spring Security handled by DaoAuthenticationProvider.

Finally, we take a look at the Authentication (Authentication information) structure, it is an interface that we mentioned earlier UsernamePasswordAuthenticationToken is one of its implementation:

Public Interface Authentication extends Principal, Serializable {(1) Collection<? extends GrantedAuthority> getAuthorities(); (2) Object getCredentials(); (3) Object getDetails(); (4) Object getPrincipal(); (5) Boolean isAuthenticated(); void setAuthenticated(boolean var1) throws IllegalArgumentException; }Copy the code
  • (1) Authentication is the interface in the Spring Security package, directly inherits from the Principal class, and Principal is located in the java.security package. It represents an abstract principal identity. Any principal has a name and therefore contains a getName() method.

  • Orities (2) getAuthorities(), a list of permission information, which by default is some implementation class for the GrantedAuthority interface, usually a string of columns that represent permission information.

  • (3) getCredentials(), which are the password characters entered by users. They are usually removed after authentication to ensure security.

  • (4) getDetails(), the implementation interface in the web application is usually WebAuthenticationDetails, which records the IP address of the visitor and the value of the sessionId.

  • (5) getPrincipal(), identity information. In most cases, it returns the implementation class of UserDetails interface. UserDetails represents the user’s details, and the UserDetails extracted from Authentication is the information of the current login user. It is also one of the commonly used interfaces in frameworks.

UserDetailsService

Know UserDetailsService

Now we know now DaoAuthenticationProvider dealt with web forms Authentication logic, after the success of the certification both get an Authentication (UsernamePasswordAuthenticationToken implementation), It contains the Principal of identity. This identity information is an Object, and in most cases it can be forcibly converted to a UserDetails Object.

DaoAuthenticationProvider contains a UserDetailsService instance, it is responsible for user information extraction according to the user name populated UserDetails (including the password), Then go contrast UserDetailsService DaoAuthenticationProvider extracting user password password matches with the user submits as the authentication key to the success of the basis, Therefore, you can define custom authentication by exposing the custom UserDetailsService as a Spring bean

public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }
Copy the code

Many people confuse the DaoAuthenticationProvider and the duties of a UserDetailsService UserDetailsService actually only from a particular place (typically a database) to load user information, that’s all. And DaoAuthenticationProvider duty is bigger, it completed the full recognition process, at the same time, will fill the populated UserDetails to Authentication.

As mentioned above, UserDetails is the user information. Let’s take a look at it:

public interface UserDetails extends Serializable { Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); }

Copy the code

It is similar to the Authentication interface in that both have username, authorities. The getCredentials() in Authentication need to be treated differently from the getPassword() in UserDetails. The former are the password credentials submitted by the user and the latter are the passwords actually stored by the user. Authentication is actually a comparison between the two. The getAuthorities() of Authentication is really shaped by the getAuthorities() of UserDetails. Remember the getDetails() method in the Authentication interface? The UserDetails UserDetails are populated after AuthenticationProvider authentication.

By implementing the UserDetailsService and UserDetails, we can complete the extension of the method of obtaining user information and the user information field.

Spring Security provided by InMemoryUserDetailsManager certification (memory), JdbcUserDetailsManager (JDBC certification) is the implementation class, UserDetailsService The main difference is simply loading the user from memory or from the database

The main process for obtaining a token

  • The user initiates a request to obtain the token.
  • The filter verifies that path is an authenticated request /oauth/token, and if false returns no further action.
  • The filter generates an Authentication object through a clientId query.
  • It then generates a UserDetails object from username and the generated Authentication object and checks if the user exists.
  • All of the above passes go to the postAccessToken method of address/Oauth/Token, which is TokenEndpoint.
  • The postAccessToken method validates the Scope, and then validates whether it is a refreshToken request, etc.
  • The Grant method in AbstractTokenGranter is then called.
  • Grant method called AbstractUserDetailsAuthenticationProvider authenticate method, through the username and the Authentication object to retrieve the user exists.
  • The OAuth2AccessToken object is then retrieved from the tokenStore using the DefaultTokenServices class.
  • The OAuth2AccessToken object is then wrapped into the response stream and returned.

Code screenshot combing process

  • Client credentials are parsed in the format of Basic space + client_ID :client_secret Base64 encrypted value

  • ① An important filter

  • ② Here is the attemptAuthentication method in ①


  • ③ Here is the authenticate method called in ②

  • (4) this is a (3) call AbstractUserDetailsAuthenticationProvider authenticate method of a class

  • 5. This is a DaoAuthenticationProvider retrieveUser method of a class (4) in the call

  • 6 here for 5. Call ClientDetailsUserDetailsService class loadUserByUsername method, after the execution and execution (4) after returning method


  • All landowners here for (4) call the DaoAuthenticationProvider class additionalAuthenticationChecks method, performed mainly filter is performed here, follow-up will enter/request/token mapping method.

  • TokenEndpoint = postAccessToken; TokenEndpoint = postAccessToken


  • ⑨ is the Grant method of the AbstractTokenGranter class called in ⑧

  • Attending here for calls in the pet-name ruby ResourceOwnerPasswordTokenGranter getOAuth2Authentication method in class



My side recreated him

  • Attending (1) of the custom here for attending the call CustomUserAuthenticationProvider authenticate method in the class, here to check the user password is correct, the execution of the returns pet-name ruby perform follow-up method.

  • ⑩② This is the createAccessToken method in DefaultTokenServices called in ⑨

  • ⑩③ This is the getAccessToken method of RedisTokenStore called in 12. After executing this method, we will continue to return to ⑧ to execute the subsequent methods.

  • ⑩④ In ⑧, the token needs to be wrapped and returned to the stream

Daily for praise

Ok, everybody, that’s all for this article, you can see people here, they are real fans.

Creation is not easy, your support and recognition, is the biggest motivation for my creation, we will see in the next article

Six pulse excalibur | article “original” if there are any errors in this blog, please give criticisms, be obliged!