I just announced the newSpring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

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:

@Autowired
private MyUserDetailsService userDetailsService;

@Override
protected void configure(AuthenticationManagerBuilder auth)
  throws Exception {
    auth.authenticationProvider(authenticationProvider());
}

@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.

I just announced the new Spring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

newest oldest most voted
Notify of
akuma8
Guest
akuma8

Hi,

Thanks again for all your tutorials. I am trying to implement the same thing but it doesn’t work and I can’t find the reason.Is there a way to enable Spring Security error logging messages? It could help me to debug if Spring Security could send me the cause of the failure.

I added the tag in my xml configuration but nothing is displayed in the Eclipse console.

Thanks again.

Here my project in Github : https://github.com/akuma8/chicowaProject

Grzegorz Piwowarek
Guest
Grzegorz Piwowarek

Could you point us to the place where Spring Security gets configured? I could not manage to find it in the configuration package or in resources directory.

akuma8
Guest
akuma8

The xml configuration is in : /WEB-INF/Spring/configurationSpring-security.xml
The implementation of UserDetailsService is in : src/main/com.chicowa.security.ChicowaUserDetailsService.java
I also tried to add a log4j.xml (/src/main/resources/log4j.xml) in the purpose to display the debug messages sent by Spring Security but nothing works.
Regarding Spring Security authentication the 2 others configurations (in-memory and jdbc) work fine but it’s not enough because I can’t manage blocked accounts and other stuffs offered by the custom UserDetailsService.
All my comments in the project are in French, I’ll try to change them.
Many thanks for your reply and happy new year 😊

Eugen Paraschiv
Guest

Quick note – it sounds like you simply need to configure the log level for the relevant package (org.springframework.security). It looks like you’re using Log4J, so it should be simple enough to set that to DEBUG or TRACE (only while you’re working on the problem of course). As soon as you do that you should start seeing the log output.
Hope that helps. Cheers,
Eugen.

akuma8
Guest
akuma8

I tried several configurations but any DEBUG or TRACE message is displayed. I’m definitely wrong maybe.

Eugen Paraschiv
Guest

It sounds like your logging config isn’t working then. My suggestion is – have a look at a working project (any of the Spring Security modules in the tutorials project should be fine – and copy the logging config (and dependencies) from there. With your logging properly configured, you should naturally see these statements in your log.
Cheers,
Eugen.

Alexander Loginov
Guest
Alexander Loginov

Hi, this solution does not work me also. After some investigation and debugging, I found the following issue in Java configuration (xml configuration seems to be correct). You can have two alternatives: 1. set everything related to authProvider in configure method (authenticationProvider with userDetailsService and passwordEncoder) and use methods userDetailsService and encode as getters (not beans), OR 2. set nothing in configure method and use bean authenticationProvider for configuration of authenticationProvider (encode should not be bean, because it is used as getter in authenticationProvider) In your code you explicitly set userDetailsService in configure method, and Spring will not use beans… Read more »

Loredana Crusoveanu
Guest
Loredana Crusoveanu

Hello Alexander. I think the confusion here is due to the fact that the bean injection was not pasted in the article. But in the code this is done like this:


@Autowired
private MyUserDetailsService userDetailsService;

So you can see that Spring will use our custom bean.

You make a good point about the configure method.

We will update the article. Thanks for pointing out the issue.