I have a Spring Boot app with MySQL. I can save Users in the database but when I try to login, it keeps saying that the username or password is incorrect. Even when I hard code an User, it still doesn't work.
I created the setup using the JavaBrains tutorial and their code on GitHub.
This is the code I'm using.
Security config:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize -> authorize
.antMatchers("/static/**", "/index").permitAll()
.antMatchers("/premium/**").hasAuthority("PREMIUM")
.antMatchers("/user/**").hasAuthority("USER")
)
.formLogin(formLogin -> formLogin
.loginPage("/login")
.failureUrl("/login-error")
);
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
My UserDetailsService
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = userRepository.findByUsername(username);
user.orElseThrow(() -> new UsernameNotFoundException("Can't find user " + username));
return user.map(MyUserDetails::new).get();
}
}
My UserDetails
public class MyUserDetails implements UserDetails {
private String username;
private String password;
private boolean isEnabled;
private List<GrantedAuthority> authorities;
public MyUserDetails(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.isEnabled = user.isEnabled();
this.authorities = Arrays.stream(user.getAuthorities().split(","))
.map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
}
My UserRepository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
User
@Entity(name="Users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String username;
private String password;
@Transient
private String passwordConfirm;
private boolean isEnabled;
private String authorities;
private String isPremium;
private LocalDateTime premiumExpiryDate;
// getters and setters
}
Login form on the login page
<p th:if="${loginError}" class="error">Wrong user or password</p>
<form th:action="@{/login}" method="post" class="login100-form validate-form p-l-55 p-r-55 p-t-178">
<span class="login100-form-title">
Sign In
</span>
<div class="wrap-input100 validate-input m-b-16" data-validate="Please enter username">
<input class="input100" type="text" name="username" placeholder="Username">
<span class="focus-input100"></span>
</div>
<div class="wrap-input100 validate-input" data-validate = "Please enter password">
<input class="input100" type="password" name="password" placeholder="Password">
<span class="focus-input100"></span>
</div>
<div class="text-right p-t-13 p-b-23">
<span class="txt1">
Forgot
</span>
<a href="#" class="txt2">
Username / Password?
</a>
</div>
<div class="container-login100-form-btn">
<button class="login100-form-btn">
Sign in
</button>
</div>
</form>
I don't have a POST mapping for the login as it is supposed to be provided by Spring security. However I suspect the problem must be somewhere there, because I had log statements in the UserDetails and in the UserDetailsService but none of those got invoked.
Can you help me figure out what is the problem here?
I figured it out. There were two problems.
The system was using default
inMemoryUserDetailsManager
instead of my UserDetailsService implementation. I don't know how to turn the inMemoryUserDetailsManager off, but I found out how to use my implementation. You need to annotate the service with @Service("userDetailsService")
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
...
The second problem were the users. They need to have the value of 'enabled' set to true. If it is set to false, the Spring regards them as inactive.
public void saveUser(User user) {
user.setAuthorities("USER");
user.setEnabled(true);
...
Now it is working for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With