javaspring-bootauthentication

Springboot: Where to extend UserDetailsService?


I'm new to springboot and I dived into a project to learn. I have a UserService and a UserService java file. I'm gonna be needing to use UserDetailsService extended but I don't know where to extend it?

usecase: retrieving username in a separate JWTAUTHFILTER java file

if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null){
          UserDetails userDetails = userService.findByUsername(userEmail);
            
        }

My UserService.java



public interface UserService {
    UserDto createUser(UserDto user);
   
}

My Impl class:



@Service
public class UserImpl implements UserService {

    private final UserRepository userRepository;
    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserImpl(final UserRepository userRepository){
        this.userRepository = userRepository;
    }

    @Override
    public UserDto createUser(UserDto user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        UserEntity userEntity = userToUserEntity(user);
        userRepository.save(userEntity);
        return user;
    }

    @Override
    public Optional<UserDto> findByUsername(String username) {
        Optional<UserEntity> userName = userRepository.findByUsername(username);
        return userName.map(user -> userEntityToUserModel(user));
    }

    

    private UserEntity userToUserEntity(final UserDto user){
        // UserEntity userEntity = new UserEntity();
        // userEntity.setUsername(user.getUsername());
        // userEntity.setId(user.getId());
        // userEntity.setPassword(user.getPassword());
        // userEntity.setRole(user.getRole()); 
        return UserEntity.builder()
                .id(user.getId())
                .username(user.getUsername())
                .role(user.getRole())
                .password(user.getPassword())
                .build();
    }

    private UserDto userEntityToUserModel (final UserEntity userEntity){
        return UserDto.builder()
                .id(userEntity.getId())
                .password(userEntity.getPassword())
                .role(userEntity.getRole())
                .username(userEntity.getUsername())
                .build();
    }

    



}

I'm so confused, the tutorial that I'm using isn't using DTO and a separated Service and service impl, can someone help me out.


Solution

  • Your CustomUserDetailsService can look like this:

    public class CustomUserDetailsService implements UserDetailsService {
        // You can autowire your UserService class here
    
        @Override
        public UserDetails loadUserByUsername(String userEmail) {
            if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
              // In your initial implementation, you tried to store the value below in a UserService object, but your findByUsername() method returns an Optional<UserDto>
              Optional<UserDto> userDtoOptional = userService.findByUsername(userEmail);
              if (userDtoOptional.isEmpty()) { return null; }
    
              UserDto userDto = userDtoOptional.get();
    
              // Now, you need to convert your UserDto data into a UserDetails object. I'm going to assume that your UserDto class has a field called username and one called password. But you can customize it by your choice.
              return User.withUsername(userDto.getUsername()).password(user.getPassword()).build();
            }
        }
    }
    

    This is pretty much it. Spring Security requires a bean of type UserDetailsService for checking if the user exists when logging in (it takes the whole User entity out of the repository, in order to also do later password checks in its logic).