The Master Class of " Learn Spring Security " is out:
>> CHECK OUT THE COURSE
1. OverviewIn this article, we will show how to create a custom database-backed UserDetailsService for authentication with Spring Security.
2. UserDetailsServiceThe UserDetailsService interface is used to retrieve user-related data. It has one method named loadUserByUsername() which finds a user entity based on the username and can be overridden to customize the process of finding the user.
It is used by the DaoAuthenticationProvider to load details about the user during authentication.
3. The User ModelFor storing users, we will create a User entity that is mapped to a database table, with the following attributes:
@Entitypublic class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, unique = true)
private String username;
private String password;
//standard getters and setters
} 4. Retrieving a User
For the purpose of retrieving a user associated with a username, we will create a DAO class using Spring Data by extending the JpaRepository interface:
public interface UserRepository extends JpaRepository<User, Long> {User findByUsername(String username);
}
5. The UserDetailsService
In order to provide our own user service, we will need to implement the UserDetailsService interface.
We’ll create a class called MyUserDetailsService that overrides the method loadUserByUsername() of the interface.
In this method, we retrieve the User object using the DAO , and if it exists, wrap it intoa MyUserPrincipal object, which implements UserDetails , and returns it:
@Servicepublic class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
return new MyUserPrincipal(user);
}
}
The MyUserPrincipal class is defined as follows:
public class MyUserPrincipal implements UserDetails {private User user;
public MyUserPrincipal(User user) {
this.user = user;
}
//...
} 6. Spring Configuration
We will demonstrate both types of Spring configurations: XML and annotation-based, which are necessary in order to use our custom UserDetailsService implementation.
6.1. Annotation ConfigurationUsing Spring annotations, we will define the UserDetailsService bean, and set it as a property of the authenticationProvider bean, which we inject into the authenticationManager :
@Overrideprotected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
} 6.2. XML Configuration
For the XML configuration, we need to define a bean with type MyUserDetailsService , and inject it into Spring’s authentication-provider bean:
<bean id="myUserDetailsService"class="org.baeldung.security.MyUserDetailsService"/>
<security:authentication-manager>
<security:authentication-provider
user-service-ref="myUserDetailsService" >
<security:password-encoder ref="passwordEncoder">
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="passwordEncoder"
class="org.springframework.security
.crypto.bcrypt.BCryptPasswordEncoder">
<constructor-arg value="11"/>
</bean> 7. Conclusion
In this article, we’ve shown how to create a custom Spring-based UserDetailsService backed by persistent data.
The implementation can be found in the GitHub project this is a Maven based project, so it should be easy to import and run as it is.