0

I am a newbie in spring boot. I'm using basic thymeleaf form login. But when I login it returns "localhost:8080/login?error=true". I don't know why. My username and password in the database are correct. Maybe I must add a new controller with post method? please help me

And here, this is my security config class

protected void configure(HttpSecurity http) throws Exception {
    logger.info("-----configure(HttpSecurity http)");
    http.authorizeRequests()
                .antMatchers("/**").permitAll()
                .antMatchers("/user/**").hasAnyRole("USER")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/home")
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .and().csrf().disable();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    logger.info("-----configureGlobal(AuthenticationManagerBuilder auth)");
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}

login form page

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
    <h2>Stacked form</h2>
    <form th:action="@{/login}" method="post">
        <div class="form-group">
            <input type="text" name="username" id="username" class="form-control input-lg"
                   placeholder="UserName" required="true" autofocus="true"/>
        </div>
        <div class="form-group">
            <input type="password" name="password" id="password" class="form-control input-lg"
                   placeholder="Password" required="true"/>
        </div>
        <div class="form-group form-check">
            <label class="form-check-label">
                <input class="form-check-input" type="checkbox" name="remember"> Remember me
            </label>
        </div>
        <a class="btn btn-success" th:href="@{'/register'}" role="button">Register</a>
        <button type="submit" class="btn btn-primary">Login</button>
    </form>
</div>
</body>
</html>

My controller

    @GetMapping("/login")
    public String login() {
        return "/login";
    }

The entity

@Entity(name = "dbo_user")
public class User {
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    @Id
    private int id;
    private String email;
    private String password;
    private String username;
}

2 Answers2

2

First of all, User class has to implement UserDetails interface like this: // userdetails methods

@Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.roles.stream().map(SimpleGrantedAuthority::new).collect(toList());
    }


    @Override
    public String getUsername() {

        return this.getEmail();
    }


    @Override
    public boolean isAccountNonExpired() {

        return true;
    }


    @Override
    public boolean isAccountNonLocked() {
        return true;
    }


    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }


    @Override
    public boolean isEnabled() {
        return true;
    }

    @Transient
    private List<String> roles = Arrays.asList("ROLE_USER");
    public List<String> getRoles() {
        return roles;
    }

2nd you need a class that implements UserDetailsService like this:

@Service("customCustomerDetailsService")
public class CustomUserDetailsService implements UserDetailsService  {

    @Autowired
    private CredentialRepository users;    

    @Override
    public UserDetails loadUserByUsername(String email)  {

      return this.users.findByEmail(email)
            .orElseThrow(() -> new UsernameNotFoundException("Username: " + email + " not found"));


    }

}

Then you autowire that class into your security config class

@Autowired
    CustomUserDetailsService customCustomerDetailsService;

You need to implement DAO DaoAuthenticationProvider in your security config class like this:

@Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService());
        authProvider.setPasswordEncoder(encoder());

        return authProvider;

I'm quite sure this question would have been answered on this platform.

tksilicon
  • 3,276
  • 3
  • 24
  • 36
  • why user class should implement UserDetails interface? – Patrick Nov 21 '19 at 09:17
  • That is where you set which class variable like email or username that is uniquely used to authenticate the user when accessing the database by Spring Security. Have you seen any tutorial on Spring security? Like the official tutorial? – tksilicon Nov 21 '19 at 09:21
  • yes I know spring-security. Never seen why user should implement userdetails interface. Do you have a source for that? And can you provide this part to your answer. – Patrick Nov 21 '19 at 09:33
  • Remember the userdetailsservice implemented class calls the repository which makes use of user class. When that call is made, it needs to access the entity class as userdetails. – tksilicon Nov 21 '19 at 09:50
0

Are you using thymeleaf security extras? If so, then you need to have dependency included with maven/gradle and thymeleaf namespaces on the login page.

   <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        <version>3.0.4.RELEASE</version>
   </dependency>

and

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:th="http://www.thymeleaf.org"
  xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" lang="en">
Miroslav Trninic
  • 3,327
  • 4
  • 28
  • 51