preface

We’ve already covered the main components of Authentication in one of our installments, and we’ve shared a few installments to give you an overview of the process and extension points for Web applications that use core Authentication. In this phase, we use the chapter of the first phase to focus on the most important services of Authentication Authentication core: AuthenticationMananger, AuthenticationProvider and UserDetailsService. The three top-level interfaces are expanded. The implementation of these interface services is explained through Spring Security. The purpose is to do a good job in the knowledge reserve of the core service of the guest system expansion.

Issue 5 Core Component AuthenticationManager feature

This issue’s to-do list

  1. AuthenticationMananger and ProviderMananger
  2. The Authentication and AuthenticationProvider
  3. The UserDetailsService interface and its implementation class

Zero, overall overview

This issue focuses on Authentication and several core service interfaces:

  1. AuthenticationMananger
  2. AuthenticationProvide
  3. UserDetailsServic

In addition, there are two interfaces and classes that encapsulate user identity information:

  1. Authentication
  2. UserDetails

Let’s take a look back at some of the core components of Spring Security that we used in previous installments:

The focus of this installment is clearly the three core components of the authentication section in the red box and their associated components.

AuthenticationMananger and ProviderMananger

The AuthenticationMananger is responsible for interacting with external consumers as the outermost wrapper of the entire authentication core. The AuthenticationMananger interface has and only one external service that is “authentication”. This is the service interface that the entire authentication service provides externally.

	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
Copy the code

External consumers call the Authenticate method by encapsulating the necessary information for Authentication, such as user name and password, with an Authentication pass. If no exception and null values are returned, the validation service is complete. Authentication not only contains the user’s Authentication information, such as the user name, but also encapsulates the list of all corresponding permissions under the user’s identity.

The link of identity information exchange: Authentication

In the whole process of interaction with external users, Authentication has two responsibilities. The first one is to encapsulate the parameters of Authentication request, and the second one is to encapsulate the user’s permission information. The credentials are used to store users’ credentials such as passwords. The authorities are used to store a user’s permission list. In addition to the user name and password, Details stores other information that may be used for authentication. For example, if the IP address range of the user is restricted, IP information may be stored in Details for auxiliary authentication information.

The only implementation class: ProviderMananger

In order to provide authentication services externally, the authentication interface of AuthenticationManager is implemented in Spring Security through the ProviderMananger. As an implementation class, ProviderMananger can’t only care about authenticate, the only abstract core service, like AuthenticationManager. In order to manage external input and Authentication like external return, the internal process of ProviderMananger is roughly as follows:

  1. First, look for the current external input that can be validatedAuthenticationIn the form ofAuthenticationProvider; If your own providers cannot handle validation and the current level ofManangerAnd the parentManangerPasses up to the parent layerManangerTo process;
  2. Then, because the Details information is passed in externally, it is authenticated internallyAuthenticationIt is not carried from persistence or other data sources and is written externally before returningAuthentication;
  3. Finally, if necessary, remove sensitivities from external authentication requests, such as leaving the password for request authentication blank. To understand theProviderManangerI’ve done three pieces of work, and I get the idea even though there’s only one validation frameworkProviderManagerIt is exposed externally, but it may be multiple internallyAuthenticationManangerandAuthenticationProviderNetwork, and ultimately the core authentication orAuthenticationProvider. The core looks in turn in the leaf node to validate the currentAuthenticationIn the form ofAuthenticationProvider. The request is validated if support existsAuthenticationPassed to theAuthenticationProvider, entrust it for verification. Validation request in processing inputAuthentication.ProviderManangerIt does not carry out any processing, but refers to the necessary processing and treatment after the processing.

Authentication and AuthenticationProvider

Compared to AuthenticationMananger, what the AuthenticationProvider does is more explicit: it provides specific validation behavior for specific validation data. In this context, Authentication is designed to solve the question of What to authenticate, while the authenticate method is more like answering the question of How to authenticate.

Authentication in the AuthenticationProvider perspective

So let’s first discuss the design of Authentication data, namely Authentication. Authentication encapsulates information data required for Authentication, such as the user name and password in the user name scenario, mobile phone number and verification Code in the SMS verification Code, and ID and Code in the OAuth2 scenario. In short, the Authentication information used by each different Authentication protocol needs to be encapsulated as Authentication. To be more precise, Spring Security encapsulates the Authentication information of the userAfter all, the concept of token is easier to understand. The encapsulation of authentication data for all protocols provided in Spring Security is inheritedUsernamePasswordAuthenticationToken, based on the user name and password, based on the OAuth2AuthorizationCodeAuthenticationToken OAuth2, CasAssertionAuthenticationToken based on CAS. In general, we use username and password the most, whether using a database persistence-based username and password scheme or an LDAP-based username and password approach. Although authentication is slightly different in the authentication protocol implementation, the user submits nearly the same authenticated identity information whether authentication LDAP or database is used for authentication comparison, We can reuse the generic structure of AuthenticationToken — assigning username to the Principal property and Password to the CenCredentials property. This means that the most important consideration in the design of AuthenticationToken is the encapsulation of data rather than the implementation of authentication behavior.

We have solved the first problem, in that the AuthenticationProvider validation data is available through the various implementation classes AuthenticationToken passed in Authentication. The next question is how the AuthenticationProvider authenticates. We assume that the scenario is to use the user name and password of UsernamePasswordAuthenticationToken for validation. Against UsernamePasswordAuthenticationToken in Spring Security authentication is there are two main AuthenticationProvider: One is based on the model of “Dao” compared with the data layer user information validation DaoAuthenticationProvider, another is though using the same user name and password, but the verification process is more complex, And the user data is through the LdapAuthenticationProvider with LDAP service for user authentication. Here the use of the most widely used based on Dao DaoAuthenticationProvider, If you have interested in Ldap implementation believe reading again after finish the analysis of the DaoAuthenticationProvider LdapAuthenticationProvider part of the code will be easier.

DaoAuthenticationProvider

DaoAuthenticationProvider for external validation request need external transfer of identity information, the user name and password for validation. We further break this task down into two separate tasks:

  1. Obtain the data record of the corresponding user name in the data layer from the data layer;
  2. Compare external user names and passwords with those at the data layer.

Why will verify the DaoAuthenticationProvider task is decomposed into two independent tasks, the biggest reason is that both of these tasks a sense of external resources, another perception verification algorithm, are two different users may have different usage scenarios, specific implementation framework and unable to control. The first task is to get the data record of the corresponding user name in the data layer from the data layer. Our goal is to find the user identity data that we need to compare from the data layer, but in this scenario we only control the implementation of the data layer. Do you access Mysql through JDBC or Oracle through JPA, or even a Map that stores key-value pairs of user information directly from memory? The second task is to compare external user names and passwords with those of the data layer. What is the specific encryption algorithm? How is it done? The two problems in the DaoAuthenticationProvider cannot clear implementation. Spring Security will be the two DaoAuthenticationProvider can not be sure, there are changes in behavior are entrusted to the DaoAuthenticationProvider two important components to complete:

  1. The UserDetailsService that returns user information in the data layer by user name;
  2. PasswordEncoder that processes a user’s password through a specific encryption algorithm.

Run the UserDetailsService command to obtain the internal user identity information

The Interface location of the UserDetailsService, as you can see from its interface methods, is to provide the core components with data layer user information, which is encapsulated as UserDetails.

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

Copy the code

Once we have determined our method of obtaining user identity information, we can extend the UserDetailsService method to tell the framework how to obtain user identity information. Usually this step is a must-do with Spring Security. We wrote the following code in the first chapter to configure the UserDetailsService we use:

Public class WebSecurityConfig extends WebSecurityConfigurerAdapter {/ / inject new UserDetailsServiceBean @ Bean public UserDetailsServiceuserDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        returnmanager; }}Copy the code

That time we used memory key-value pairs to store and retrieve user records. Spring Security has already provided a JDBC-based implementation of UserServiceDetails and the corresponding template DDL:

create table users(username varchar_ignorecase(50) not null primary key,password varchar_ignorecase(500) not null,enabled boolean not null);
create table authorities (username varchar_ignorecase(50) not null,authority varchar_ignorecase(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);
Copy the code

The data type returned by the UserDetailsService is UserDetails, which encapsulates the user name, password, and authorization information as well as some expired and locked identifier attributes. It is not hard to see that the data encapsulated by UserDetails is very similar to Authentication. Yes, after successful authentication, DaoAuthenticationProvider internal will be populated UserDetails out of necessary data corresponding to assign values to the UsernamePasswordAuthenticationToken eventually returned to the external caller to use. We can simply think of UserDetails as the encapsulation of user identity information at the data layer. During customization, if the data structure of user information is a special structure, such as Ldap, you can extend UserDetails to customize a special structure for retrieving user data records. Here basically we already know about the DaoAuthenticationProvider two components used to get UserDetailsService part of the user’s identity records, here we introduce PasswordEncoder part of dealing with password authentication.

PasswordEncoder is used to compare passwords

Let’s continue with the above scenario and talk about validation algorithms. DaoAuthenticationProvider received the user name and password, external to submit the same DaoAuthenticationProvider also find the corresponding user name in the database user name and password. Usually, passwords stored in the database are encrypted, even though they are passwords. DaoAuthenticationProvider will need to submit the external user name and password for an encrypted process and compare. So, for example, the algorithm that we’re currently using is MD5, where the sample of the encrypted plaintext is the user’s username and the concatenated user name. If there is a request for authentication, the user name is admin and the password is password. The same encrypted password in the database is 9b02edfBC208a538. We need to do an MD5(“passwordadmin”) for the external user name and password to get 9b02EDFBC208a538, and then compare with the password field in the database, if the same, the authentication is successful. This targeting in Spring Security is calledPasswordEncoder interface is used to encrypt and compare plaintext passwords.

Spring Security provided by the default to DaoAuthenticationProvider PasswordEncoder BCryptPasswordEncoder. If BCrypt can be additional through Google to understand the encryption process. If we need customization encryption algorithms, as long as the implementation PasswordEncoder interface, and then through the Spring injection DaoAuthenticationProvider.

@Bean
public PasswordEncoder passwordEncoder() {// Customize your own PasswordEncoder by modifying the injected instancereturn new BCryptPasswordEncoder();
}
Copy the code

The PasswordEncoder section has relatively few features, and using the BCryptPasswordEncoder provided by default is usually sufficient.

At the end

In this issue we have spent a great deal of time describing the key components of the authentication core and the specific responsibilities of an implementation class based on the corresponding interface in a user name and password authentication scenario:

  1. The AuthenticationManager takes care of the processing before and after the core validation and the interaction with external callers;
  2. AuthenticationProvider is the core implementation of authentication service, and its data form is AuthenticationToken, which encapsulates the user identity and user authentication credentials used for authentication.
  3. The internal user identity information is obtained by using the UserDetailsService in AuthenticationProvider. If password processing is needed, PasswordEncoder is introduced.
  4. UserDetails encapsulates the internal structure of the user’s information. Before returning Authentication externally, the AuthenticationProvider usually copies the UserDetails’ necessary data into the AuthenticationToken that is returned externally.

Over the course of several installments, we have basically covered the entire Spring Security implementation of authentication components, processes, and specific scenarios. Starting with the next installment, we will start to explain the design and concepts of the access control section and the framework configuration section. At the same time will be through some scenes of actual combat strong related framework concepts and design concepts. Thank you, and I’ll see you next time.