preface
Last time we showed you how to add the Spring Security framework to a SpringBoot application in the simplest way and enable it to perform user authentication and access control authorization services for the application. In this installment, we will focus on user authentication, which can be done from the perspective of the framework’s core and integration with Spring Web. We will start from the bottom up, starting with the framework’s core areas, and finally expanding on how Spring Security supports and services Spring Web. In order to focus on the core business, a portion of the source code has been processed to make it easier to understand the responsibilities and functions of the core design and related classes, which may be different from the framework’s own code.
Phase II Authentication Core Introduction
This issue’s to-do list
- Authentication Core-related components and processes
- User name – and password-based authentication process demonstration
1, Authentication core related components and processes
Authentication is the Authentication, commonly said is the user login operation, in our general design, login submission and login successfully obtained is the user record information; The entire authentication service provides only one interface to authenticate login. Here we have a few preset questions that you can try to answer while learning about the core components:
- In which class are the username and password submitted during login encapsulated?
- Which interface is responsible for receiving the username and password submitted for login, what classes are returned, and what information is encapsulated?
- How does the authentication service check whether the user name and password are correct? And how to obtain the existing user information?
First, in our general design, the input of login information is abstracted into a form or, more simply, a method signature such as User authentication(String Username,String password). Spring Security has oneClass, the user name and password we enter are encapsulated as the user’s principal identity and the user’s authentication credentials.
In addition, Authentication not only encapsulates the attributes used for logging in, but also stores the list of its associated permissions in Authorities after completing the Authentication operation. The initial and final state of the whole authentication is just like when we go to the canteen for lunch and give the lunch box and card to the aunt. As long as there is money in the meal card, the aunt will fill the corresponding lunch box for you. You hand out a box and a card, and bring back a box and a card. No matter whether the lunch box is two-tier or three-tier in the future, whether the food card is a physical card or alipay has nothing to do with the process of ordering food.
And this meal service authentication service takes the form of
Authentication authenticate(Authentication authentication)
Copy the code
And the lunch lady who gave us the ultimate authentication service, her name is.
- In the preset user information database to find the current need to authenticate user records;
- Verify that the Authentication credentials and user names in Authentication are the same as those queried in the preset Settings.
In the actual development, our system can support a variety of authentication implementations, which may be to compare whether the preset user password is consistent, or whether the value of a token is consistent, or simply consider that the AuthenticationProvider implements how to authenticate the service, usually we will also be called “authentication mechanism”. Spring Security already provides a variety of authentication mechanisms. Take a look at the class names listed below to get an idea of the corresponding authentication mechanisms:
- OAuth2LoginAuthenticationProvider
- CasAuthenticationProvider
- JwtAuthenticationProvider
- GoogleAccountsAuthenticationProvider these AuthenticationProvider against their different Authentication mechanisms are in the business logic of the implementation, the second task, verify the Authentication Authentication credentials. These AuthenticationProviders also need to obtain the preset user information from the preset user information database to complete the comparison work. Spring Security will get user preset information services, mentionedIn:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
Copy the code
The preset user information is encapsulated in the class of UserDetails. UserDetails mainly contains basic Authentication, including user name, password, permission list and other basic user information attributes.
Now that we have an overview of the main responsibilities and work of the AuthenticationProvider and UserDetailService classes, let’s consider the last question. The service of UserDetailsService returns UserDetails, The AuthenticationProvider service returns Authentication. Who is responsible for the logic that encapsulates UserDetails as Authentication? In Sping Security, the UserDetailsService only provides an action to return user information based on the user name. The work of assembling the UserDetails into Authentication and returning it to the caller is also done by the AuthenticationProvider. Back to our original canteen, some of our Windows have some special services. For example, the aunts in some Windows can speak English and support English ordering, and the aunts in some Windows can use Alipay to settle accounts and support Alipay ordering. While these aunts support a variety of postures, they are essentially a service that gives money with one hand and food with the other. After a few years, our canteen lunch ladies were all talented but couldn’t handle the expansion of college enrollment and the number of students doubled. Recently, some students have reported that if they don’t skip the last class in the morning to go to lunch, they can buy lunch at 1pm. According to the actual situation, the school leaders decided to set up a group of employees at each window. An aunt was responsible for taking food and vegetables, while an uncle was responsible for ordering, swiping cards and loading food into lunch boxes. That’s right, the uncle who takes the food is the UserDetailService, and the aunt who orders the food, swiping the card, and loading the food is the AuthenticationProvider. Rice aunt still support a variety of versatile students of rice posture, and take food uncle two eyes as long as looking at the canteen huge pot dishes on the line. In the following month, not only the efficiency of the canteen was improved and students could buy lunch at 12 o ‘clock, but also the attendance rate of the last class in the morning was greatly improved. Finally, we introduce the final characterProviderManager is configured with various authentication services in addition to the authentication user information service. ProviderManager is also an implementation class for the AuthenticationManager interface, which is the only externally provided user authentication service interface. The AuthenticationManager itself does not implement the logic to verify the user’s identity but delegates it to the AuthenticationProvider it configures.
Back to our university canteen for the last time, in order to make it more convenient and fast for female otaku who do not go out for a long time to eat lunch, we can order directly through the ordering machine at the entrance of the canteen in the future. Students choose their favorite dishes at the ordering machine, swipe their cards and get the food they want at the window. I had to wait in line twice to eat clay pot rice and pizza at the international student window. Now, with this machine, I can order food from two Windows at a time and wait at the door. The overseas students almost wait in seconds to get their meal, while the Cantonese food window has to wait in front of the canteen. Now the emergence of the ordering machine may be the first time since the Opium War to realize the equality of human rights between China and foreign countries, and everyone has to queue up in front of the ordering machine honestly. Aunt canteen dozen rice don’t directly in the face of all kinds of fancy dozen rice position of students, as long as the watch order shown on the machine system to play the order and then uncle configuration and rice and food lunch box, and then determine the meal card is effective to carry out the work, rice aunts are simple reflect the work a lot, have a mood to square dance at night. Here we have covered the core components of the basic Authentication section, responsible for global configuration and directly facing the callerOrdering machine, responsible for the complete verification of user information servicesRice aunt, responsible for obtaining preset user information, from the big pot rice dishes to take food to take foodUncle. In the next section we will simulate our own with a simple Java exampleThe dining roomSpring Security’s Authentication core process.
2. Demonstration of authentication process based on user name and password
First, we need to assemble a service that can provide authentication users, so we just need an AuthenticationProvider, and the AuthenticationProvider itself doesn’t get the preset user information. So we also need to configure an implementation component for the UserDetailsService.
/ / hire a set of dining room dozen rice uncle aunt UserDetailsService UserDetailsService = new InMemoryUserDetailsManager (); AuthenticationProvider provider = new DaoAuthenticationProvider(); / / assembly ((DaoAuthenticationProvider) provider.) setUserDetailsService (userDetailsService);Copy the code
Our side using the InMemoryUserDetailsManager based on user identity information management and memory management of the preset DaoAuthenticationProvider based on user name and password to verify our user identity information.
Let’s create our first user id in memory. The user name is user, the password is password, and the role is user:
((InMemoryUserDetailsManager) userDetailsService)
.createUser(User
.withUsername("user").password("password").roles("USER")
.build());
Copy the code
Then we simulate the first Authentication request, we created a Authentication, its implementation as a UsernamePasswordAuthenticationToken based on user name and password. We need to verify the user name user, password bit password
Authentication authentication = new UsernamePasswordAuthenticationToken("user"."password");
Copy the code
We then invoke the validation service and print on the console
Authentication result = provider.authenticate(authentication);
System.out.println(result);
Copy the code
The final section of the log on the console will show that the returned Authentication has obtained the preset USER permission.
Granted Authorities: ROLE_USER
Copy the code
What if we enter the wrong username and password? Let’s try the following code:
Authentication authentication = new UsernamePasswordAuthenticationToken("user"."wrong");
Authentication result = provider.authenticate(authentication);
System.out.println(result);
Copy the code
In the case that the entered Authentication identity information cannot match the preset identity information, Spring Security AuthenticationProvider will throw org. Springframework. Security, authentication, BadCredentialsException exception is used to inform the User name and password to the User The preset information obtained by DetailsService does not match.
Finally, we mask our direct connection to the AuthenticationProvider, which we use to provide us with multiple Provider services. When initializing the ProviderManager, we need to set the list of all authenticationProviders managed by the Manager, and then call the Authenticate authentication method as well to achieve the same effect.
List<AuthenticationProvider> providers = new ArrayList<>();
providers.add(provider);
AuthenticationManager manager = new ProviderManager(providers);
Authentication result = manager .authenticate(authentication);
System.out.println(result);
Copy the code
So why an additional layer of encapsulation of AuthenticationManager? Let’s consider the following scenario if our system also supports user – and password-based services whose data is retrieved from the database, and also supports user authentication services that use tokens to authenticate tokens from Redis. In a situation like this, We simply add an AuthenticationProvider based on Token authentication to the AuthenticationProvider list of AuthenticationManager (its UserDetailsService is Redis) API implementation). Such configuration changes do not affect the core to external exposure of the service interface and related Authentication parameters.
At the end
After the baptism of the university canteen, we have basically explained the core components and main processes of Authentication server in Spring Security. In the next installment, we’ll explain how Spring Security supports Spring Web applications.