Spring Security Login With Database Authentication in Spring Boot

In this example, we will learn how to use a custom login with database authentication using spring security in the spring boot example.
In this example, we will enter credentials like username and password in a custom login form and submit. Then validate the entered credential in a database table.

Table of content

1. Keep Eclipse IDE ready(STS integrated)
2. Create a Spring Boot Starter Project 
3. Maven Dependency
4. Define Database configuration in the application.properties file
5. Create entity class
6. Create a repository
7. Create a service
8. Create a view page
9. Create a Controller class
10. Create a Spring Security Config class
11. Insert data into the database
12. Run the Application
13. Conclusion

1. Keep Eclipse IDE ready(STS integrated)

Refer to this article How to Create Spring Project in IDE to create Spring Boot Project in Eclipse IDE.

2. Create a Spring Boot Starter Project 

Add the following dependencies: 
• Spring Web 
• Spring Security
• Thymeleaf
• MySQL Driver
• Spring Data JPA

Project Structure of Login with Database Authentication Spring Security

spring_security_login_with_database_authentication_in_spring_boot

3. Maven Dependency

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.11</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springjava</groupId>
    <artifactId>Spring_Security_Login_With_Database_Authentication</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Spring_Security_Login_With_Database_Authentication</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>16</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!-- <scope>runtime</scope> -->
            <version>5.1.32</version>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

4. Define Database configuration in the application.properties file

#Mysql Database
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/poc_db?useSSL=false
spring.datasource.username=root
spring.datasource.password=mysql
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true

5. Create entity class

Role.java

package com.springjava.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;

    public Role() {

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

User.java

package com.springjava.entity;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
  
   private String name;
    @Column(nullable = false, unique = true)
    private String username;
    @Column(nullable = false, unique = true)
    private String email;
    @Column(nullable = false)
    private String password;

    @ManyToMany
    @LazyCollection(LazyCollectionOption.FALSE)
    private Set<Role> roles;
    
    public Integer getId() {
          return id;
      }

      public void setId(Integer id) {
          this.id = id;
      }

      public String getName() {
          return name;
      }

      public void setName(String name) {
          this.name = name;
      }

      public String getUsername() {
          return username;
      }

      public void setUsername(String username) {
          this.username = username;
      }

      public String getEmail() {
          return email;
      }

      public void setEmail(String email) {
          this.email = email;
      }

      public String getPassword() {
          return password;
      }

      public void setPassword(String password) {
          this.password = password;
      }

      public Set<Role> getRoles() {
          return roles;
      }

      public void setRoles(Set<Role> roles) {
          this.roles = roles;
      }
}

6. Create a repository

UserRepository.java

package com.springjava.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.springjava.entity.User;
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsernameOrEmail(String username, String email);
}

7. Create a service

UserDetail.java

package com.springjava.service;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.springjava.entity.User;
import com.springjava.repository.UserRepository;
@Service
public class UserDetail implements UserDetailsService {
@Autowired    
UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException{
        User user = userRepo.findByUsernameOrEmail(username, username);
          if(user==null){
                throw new UsernameNotFoundException("User not exists by Username");
               }
        Set<GrantedAuthority> authorities = user.getRoles().stream()
                .map((role) -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toSet());

        return new org.springframework.security.core.userdetails.User(username,user.getPassword(),authorities);
    }
}

8. Create a view page

Create a view page under src/main/resources/templates.

login.html

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
    rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand">Spring Security Login With Database Authentication</a>
            <button class="navbar-toggler" type="button"
                data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
        </div>
    </nav>
    <br />
    <br />
    <div class="container">
        <div class="row">
            <div class="col-md-6 offset-md-3">

                <div th:if="${param.error}">
                    <div class="alert alert-danger">Invalid Username or Password</div>
                </div>
                <div th:if="${param.logout}">
                    <div class="alert alert-success">You have been logged out.</div>
                </div>

                <div class="card">
                    <div class="card-header">
                        <h2 class="text-center">Login</h2>
                    </div>
                    <div class="card-body">
                        <form method="post" role="form" th:action="@{/login}"
                            class="form-horizontal">
                            <div class="form-group mb-3">
                                <label class="control-label"> Username</label> <input type="text"
                                    id="username" name="username" class="form-control"
                                    placeholder="Enter username" />
                            </div>

                            <div class="form-group mb-3">
                                <label class="control-label"> Password</label> <input
                                    type="password" id="password" name="password"
                                    class="form-control" placeholder="Enter password" />
                            </div>
                            <div class="form-group mb-3">
                                <button type="submit" class="btn btn-primary">Login</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

home.html

<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
          rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container-fluid">
        <a class="navbar-brand">Spring Security Login With Database Authentication</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                <li class="nav-item">
                    <a class="nav-link active" aria-current="page" th:href="@{/logout}">Logout</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<br /><br />

<body>
<div class="container">
    <div class="row">
        <h1> Welcome to Spring Security world!</h1>
    </div>
</div>
</body>
</html>

9. Create a Controller class

HomeController.java

package com.springjava.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {
    @GetMapping("/")
    public String greeting() {
        return "index";
    }

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

    @GetMapping("/admin")
    public String admin() {
        return "admin";
    }
    
    @GetMapping("/manager")
    public String manager() {
        return "manager";
    }
    
    @GetMapping("/employee")
    public String employee() {
        return "employee";
    }
    
    @GetMapping("/logout")
    public String logout() {
        return "redirect:/login";
    }
}

10. Create a Spring Security Config class

SecurityConfig.java

package com.springjava.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
public class SecurityConfig {
    
        @Bean
        public static PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }

        @Bean
        public SecurityFilterChain filterSecurity(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .authorizeHttpRequests((authorize) ->
                            authorize.anyRequest().authenticated()
                    ).formLogin(
                            form -> form
                                    .loginPage("/login")
                                    .loginProcessingUrl("/login")
                                    .defaultSuccessUrl("/")
                                    .permitAll()
                    ).logout(
                            logout -> logout
                                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                                    .permitAll()
                    );
            return http.build();
        }

}

11. Insert data into the database

INSERT INTO `user` VALUES
(1,'admin@gmail.com','admin','$2a$10$gqHrslMttQWSsDSVRTK1OehkkBiXsJ/a4z2OURU./dizwOQu5Lovu','admin'),
(2,'test@gmail.com','test'$2a$12$TYSPPDsgR1T9vpgMSavOteZoqzjGVLt7rzsqKLrGL4oQdE3rWDNru','test');

INSERT INTO `role` VALUES (1,'ROLE_ADMIN'),(2,'ROLE_USER');

INSERT INTO `user_role` VALUES (1,1),(2,2);

12. Run the Application

To run this application right-click on the application click on Run As then select the Run on Server option. After successfully running this application on the browser custom login form is shown. 
Now enter the username as admin and password as admin or username as test and password as a test.

spring_security_login_with_database_authentication_in_spring_boot

After login with a valid username and password

spring_security_login_with_database_authentication_in_spring_boot

To logout click on the Logout 

spring_security_login_with_database_authentication_in_spring_boot

13. Conclusion

In this example, we learnt how to implement spring security database authentication in the spring boot example.

Leave a Comment