CustomUserDetailsService.java
package com.stocks.stockease.security;
import java.util.Collections;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.stocks.stockease.security.internal.UserRepository;
/**
* UserDetailsService implementation that loads Spring Security user details from the database.
* Converts the User domain model's role string into a GrantedAuthority for authorization.
*/
@Service
@org.springframework.context.annotation.Profile("!docs")
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
/**
* Constructs the service with a user repository for data access.
*
* @param userRepository repository for user data access
*/
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
/**
* Loads a UserDetails instance by username, throwing UsernameNotFoundException if not found.
*
* @param username the username to look up
* @return Spring Security UserDetails with username, password, and authorities
* @throws UsernameNotFoundException if no user exists with the given username
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
// Password is BCrypt-encoded in the database; AuthenticationManager hashes the submitted password before comparing
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
Collections.singletonList(new SimpleGrantedAuthority(user.getRole()))
);
}
}