Once you tell the Spring Security Configuration that you will use a particular UserDetailsService
or only one @Service
bean is an implementation of that interface, then Spring starts using it to fetch the user by username from your persistent storage. Let's simplify the flow:
The user submits a form where fields with names app_username
and app_password
are present (as configured in Web Security Config) to the loginPage(String)
route
The form submission is intercepted by the Spring Security's Filter Chain and Spring is aware that the username is in the field app_username
and the password is in the field app_password
The configured UserDetailsService
bean is now activated, at its loadUserByUsername(String)
method is invoked and the value of app_username
field is passed (e.g. john_smith
)
As the loadUserByUsername(String)
method is by contract designed to return an implementation of UserDetails
it always returns an object which contains getUsername()
and getPassword()
methods
Spring then uses the getPassword()
method from the contract and compares the password with app_password
field (e.g. super_s3cr3t_password
)
If passwordEncoder()
is configured in the Spring Security Config or an implementation of PasswordEncoder
interface is registered as bean, then spring uses the isPasswordValid(String, String, Object)
method to verify the contents of app_password
field and the result of UserDetails.getPassword()
method
If the UserDetailsService
does not throw UsernameNotFoundException
and the fetched UserDetails
's getPassword()
matches the app_password
the filter chain continues executing the other filters, otherwise it prevents the user from logging into the application
If a code example simplifies it better, then imagine the following pseudo-java-code:
String usernameField = this.getConfiguredUsernameParameter(); // app_username
String passwordField = this.getConfiguredPasswordParameter(); // app_password
UserDetails userDetails = this.registeredUserDetailsImplementation.loadUserByUsername(request.getParameter(usernameField));
String passwordHash = userDetails.getPassword();
String rawPassword = request.getParameter(passwordField);
String salt = this.getConfiguredSalt(); // can be null
if (this.configuredPasswordEncoder.isPasswordValid(passwordHash, rawPassword, salt) {
return true;
}
return false;
Keep in mind this is not the Spring Security Code behind the scenes, but just a simplified code illustration of the explanation.