Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot login with Spring Boot Security

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?

like image 472
Jan Horčička Avatar asked May 04 '26 21:05

Jan Horčička


1 Answers

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.

like image 89
Jan Horčička Avatar answered May 06 '26 11:05

Jan Horčička



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!