The Master Class of "Learn Spring Security" is out:
1. Overview
In this article, we will show how to create a custom database-backed UserDetailsService for authentication with Spring Security.
2. UserDetailsService
The 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 Model
For storing users, we will create a User entity that is mapped to a database table, with the following attributes:
@Entity public 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 into a MyUserPrincipal object, which implements UserDetails, and returns it:
@Service public 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 Configuration
Using Spring annotations, we will define the UserDetailsService bean, and set it as a property of the authenticationProvider bean, which we inject into the authenticationManager:
@Override protected 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.