So I followed some guides on spring security with usernames and passwords, however most of them show using "InMemoryUserDetailsManager" which they say should not be used in production:
@Bean
public InMemoryUserDetailsManager userDetailsManager(){
UserDetails admin = User.withDefaultPasswordEncoder()
.username("ADMIN")
.password("123")
.roles("ADMIN").build();
return new InMemoryUserDetailsManager(admin);
}
My questions, so how should a production level version of this be setup? Is it just not using the default password encoder because it is deprecated or should I use an entirely different method of adding and storing users?
CodePudding user response:
You should implement jdbc authentication DaoAuthenticationProvider
. Checkout https://www.baeldung.com/spring-security-jdbc-authentication.
Your user details must be stored in permanent storage, not temporary storage. Also, passwords must be encrypted to avoid compromising security. So using permanent storage you can take backup or data and run queries out of it.
CodePudding user response:
You can implement custom user details service instead of using default.
@Service
public class CustomUserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
public CustomUserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user == null) {
throw ApiExceptionFactory.getApiException(ApiExceptionType.NOT_FOUND, "user");
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
user.getEnabled(),
true,
true,
true,
getAuthorities(user));
}
public Boolean isTokenValid(String token) {
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(SECRET.getBytes()).parseClaimsJws(token);
return true;
} catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
throw ApiExceptionFactory.getApiException(ApiExceptionType.LOGIN_FAILURE, "invalid credentials");
} catch (ExpiredJwtException ex) {
throw ApiExceptionFactory.getApiException(ApiExceptionType.LOGIN_FAILURE, "token expired");
}
}
@Transactional
public Boolean save(User user){
if(StringUtils.isEmpty(user.getUsername())) {
throw ApiExceptionFactory.getApiException(ApiExceptionType.BAD_REQUEST, "username");
}
if(StringUtils.isEmpty(user.getPassword())) {
throw ApiExceptionFactory.getApiException(ApiExceptionType.BAD_REQUEST, "password");
}
if(StringUtils.isEmpty(user.getEmail())) {
throw ApiExceptionFactory.getApiException(ApiExceptionType.BAD_REQUEST, "email");
}
User registeredUser = new User();
registeredUser.setUsername(user.getUsername());
registeredUser.setPassword(passwordEncoder.encode(user.getPassword()));
registeredUser.setEmail(user.getEmail());
registeredUser.setEnabled(true);
registeredUser.setRoles(user.getRoles());
User savedUser = userRepository.save(registeredUser);
Inventory userInventory = inventoryService.saveInventoryForUser(savedUser.getUsername());
return userInventory != null;
}
private Set<GrantedAuthority> getAuthorities(User user){
Set<GrantedAuthority> authorities = new HashSet<>();
for(Role role : user.getRoles()) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName().getRole());
authorities.add(grantedAuthority);
}
return authorities;
}
}
You can save user details into your repository.
@Repository
public interface UserRepository extends BaseRepository<User> {
User findByUsername(String username);
Boolean existsByUsername(String username);
Boolean existsByEmail(String email);
}
Finally add your user details into authentication manager with password encoder.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository userRepository;
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsServiceBean()).passwordEncoder(passwordEncoder());
}
@Override
public UserDetailsService userDetailsServiceBean() {
return new CustomUserDetailsServiceImpl(userRepository);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
For more details check my github repository
CodePudding user response:
Hello Please Code as the following coding
@Bean
public InMemoryUserDetailsManager createUserDetailsManager() {
UserDetails userDetails1 = createNewUser("username1", "dummy");
UserDetails userDetails2 = createNewUser("username2", "dummydummy");
return new InMemoryUserDetailsManager(userDetails1, userDetails2);
}
private UserDetails createNewUser(String username, String password) {
Function<String, String> passwordEncoder
= input -> passwordEncoder().encode(input);
UserDetails userDetails = User.builder()
.passwordEncoder(passwordEncoder)
.username(username)
.password(password)
.roles("USER","ADMIN")
.build();
return userDetails;
}
Hope it help you