In the Spring Boot authentication process, I investigated how to specify a password that I had been wondering for a long time.
We will show you how to implement authentication process with user name and password in Spring Boot and Spring Security.
The prerequisite environment is as follows.
Version | |
---|---|
Java | 1.7 |
Spring Boot | 1.5.9.RELEASE |
If you go to "Spring Boot Authentication Process", you will find many samples using loadUserByUsername
of `ʻUserDetailsService`` [^ fqcn-uds].
I have also written. → Use Basic authentication with Spring Boot
However, as shown below, the argument of loadUserByUsername
is only `ʻusername``.
UserDetailsService
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
Therefore, it cannot be handled when ** authentication process with user name and password ** is required.
For example, in the following cases, loadUserByUsername
cannot be used.
--Password hashing is performed on the DB side [^ cript], and it is necessary to include the password in the SQL parameter value. --Authentication is performed in an external library, and it is necessary to pass a user name and password set to the API.
[^ cript]: PostgreSQL crypt
function, etc.
Use ʻAbstractUserDetailsAuthenticationProvider`` [^ fqcn-audap] instead of
ʻUserDetailsService. Specifically, by creating a Bean of `ʻAuthenticationProvider
using` ʻAbstractUserDetailsAuthenticationProvider``, ** authentication process using user name and password ** can be easily implemented.
Register Authentication Provider with Java Config
@Configuration
public class MyConfigure extends WebSecurityConfigurerAdapter {
//* Basic authentication is required for all URLs to check the operation.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().realmName("My sample realm"); //Basic authentication settings
http.authorizeRequests().anyRequest().authenticated(); //Setting requests that require authentication
}
// ----------------------------------------
//Bean definition
// ----------------------------------------
@Bean
public AuthenticationProvider getAuthenticationProvider() {
//Use your own AuthenticationProvider
return new MyUserDetailsAuthenticationProvider();
}
}
Definition of your own Authentication Provider
//By inheriting AbstractUserDetailsAuthenticationProvider, it is OK to implement only retrieveUser
public class MyUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private static final String DUMMY_PASSWORD = "DUMMY_PASSWORD"; //* Since it is not used for authentication, any value can be used.(Null and empty string are NG)
private static final List<GrantedAuthority> AUTH_USER = AuthorityUtils.createAuthorityList("USER"); //* In this sample, all have this authority.
// <<< N/A >>>
@Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {}
//---
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
String userId = username;
String password = (String) authentication.getCredentials();
//Check user ID and password
boolean isValid = AuthApi.isValidUserIdAndPassword(userId, password); //* Pseudo code that authenticates with the API of the external library
if (!isValid) { throw new UsernameNotFoundException(username); }
//Implementation of UserDetails(User)Is generated and used as the return value
return new User(username, DUMMY_PASSWORD, AUTH_USER);
}
}
As I wrote at the beginning, there are a lot of samples using loadUserByUsername
, but for some reason there seemed to be few samples using passwords for authentication processing, so I looked it up and wrote it.
If you have any mistakes or improvements, please let us know.
Recommended Posts