Spring security (II) -- custom data source
preface
This note records the customization of the authentication data source of spring security, that is, the user name and password of user authentication are not modified in the configuration file (this kind of authentication is to put the data source into memory and use the data source in memory to perform authentication during operation), We will use custom data sources (data in the database) to authenticate users' access to system resources.
Overview (the text description is rather obscure. If you can't understand it, you can directly look at the code implementation below or find the video. There will be hand-painted drawings in the summary part)
The first note does not explain the authentication process of spring security. Here's an explanation:
First of all, the authentication of spring security is completed by an interface called AuthenticationManager. Under this interface, there is only one implementation class - ProviderManager by default. The specific work of authentication is completed by this implementation class.
One small detail of the ProviderManager object during authentication is that it will generate a specific instance class through the AuthenticationManager interface to be its own parent class. However, the interface has only one implementation class, that is, itself, so its own parent class generated by it is the same type as itself (typically I am my father).
In the authentication process, our ProviderManager will authenticate first. If the authentication fails, it will authenticate through its own parent class, that is, the implementation class of the same type generated by itself according to the most basic configuration (default configuration). If the authentication fails again, it means that the overall authentication fails.
In this process, the parent class generated by the ProviderManager is actually a default global authenticator, which is a global object automatically injected by SpringBoot when integrating the spring security framework and set according to the default configuration (remember this global, we will consider later). We first go through the ProviderManager itself without restrictive parent class, It means that we can customize the authentication rules (how to customize them later). At this time, we will introduce the third class - AuthenticationProvider
AuthenticationProvider is an authentication rule, which exists in ProviderManager. In this case, it is called user-defined authentication list. Later, when customizing a variety of different authentication rules for different types of resources, we will compare all authenticators except the default authenticator. As long as one passes, it means that the authentication is successful; If all user-defined authentication rules fail, the default authenticator rules will be compared. If the comparison in the default authenticator rules is passed, it also means that the authentication is passed.
Custom data source configuration
Generally speaking, there are two ways to customize data source configuration, which are as follows:
Modify the default authenticator object
In the last note, we can define a method in our custom configuration class to modify the default authentication object automatically injected when SpringBoot integrates with the spring security framework.
/** * This method operates using the AuthenticationManagerBuilder object provided by spring security injected by spring boot by default * When using this method, it must be noted that if the UserDetailsService object is externally rewritten, the externally rewritten object must be injected into the default object * * @throws Exception */ @Autowired public void initialize(AuthenticationManagerBuilder builder) throws Exception { log.info("springboot Default configuration:" + builder); // Specify that the user authentication information is stored in memory InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager(); // Specify user information data userDetailsService.createUser(User.withUsername("Reman").password("{noop}123").roles("admin","suser").build()); // Add customized user data to the default authenticator builder.userDetailsService(userDetailsService); }
In this custom method, our method name can be named arbitrarily, as long as we can modify the default authentication object internally. At the same time, we can also modify it in the simplest way.
We mainly need to modify the information of user authentication, that is, user name, password and permission information. These information is modified by the UserDetailsService instance in the AuthenticationManagerBuilder instance, so we can modify the user data by customizing the UserDetailsService configuration class, as follows:
@Bean public UserDetailsService userDetailsService(){ InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager(); userDetailsService.createUser(User.withUsername("Reman").password("{noop}123").roles("admin","suser").build()); return userDetailsService; }
Custom authenticator
We can also customize an authenticator object, and then inject the user data object defined in the previous section:
/** * This method is recommended to configure the global authentication manager * This method is to customize the object management of AuthenticationManagerBuilder. The customized object management will override the SpringSecurity object injected by SpringBoot by default * This method is convenient for us to completely customize the authentication manager in project development * * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder builder) throws Exception { // When customizing the authentication manager, you need to manually inject external data source objects into the corresponding customized management builder.userDetailsService(userDetailsService()); log.info("custom AuthenticationManager: " + builder); }
The user-defined authenticator object is a local object when it is created, that is, it can be used in the factory, but it cannot be injected externally. So we need to rewrite a method to cover:
// It is used to expose the custom AuthenticationManager object in the factory, so that the object can be injected anywhere in the project @Override // Instance an object in the factory @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
summary
This note records some basic processes and concepts of user-defined authentication data sources. Repeat here. It is recommended to directly customize the authenticator object by using the rule method to override the default injected object.
The authentication process in spring security must be understood thoroughly, otherwise the user-defined data source and some subsequent user-defined interceptors will be confused. The following hand-painted diagram shows the process and structure of the authenticator:
The above figure illustrates a simple authentication process. When we need authentication, we will first implement a class - ProviderManager in the AuthenticationManager interface. After implementation, this class will generate a parent class. However, the parent class is an interface. In the default structure, the interface has only one implementation class, so a parent class of the same type will be generated.
There can be more than one part circled by the blue dotted line in the figure. We can customize the authenticators of various rules according to resources. At the same time, there can be multiple authenticationproviders in a ProviderManager (the bottom AuthenticationProvider in the figure is flawed, it should be a list).
Specific certification process:
- Enter the user-defined authenticator (if not, enter the default injected manager object) to judge whether it complies with the authentication rules;
- Continue to enter other user-defined authenticators for judgment;
- If the rules of one of the authenticators are met, the authentication is passed
- If all user-defined authenticators do not comply with the authentication rules, enter the parent authenticator;
- If the parent authenticator passes the authentication, it means that the authentication is passed, otherwise the authentication fails.