Spring Boot Security Database Authentication Example

In this Spring Security tutorial, we will learn how to implement a custom login form with database authentication using Java, Spring Boot, Spring Security, and a MySQL database. In database authentication, the user enters login credentials (username and password) in a login form and submits it. The application then validates the entered credentials with those stored in the database.

Step 1: Create a Spring Boot Project

Using Spring Initializr

  1. Navigate to Spring Initializr: Open Spring Initializr in your browser.
  2. Configure the Project:
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 3.2
    • Group: com.rameshfadatare
    • Artifact: springsecuritydatabaseauth
    • Name: springsecuritydatabaseauth
    • Description: Demo project for Spring Boot Security Database Authentication
    • Package name: com.rameshfadatare.springsecuritydatabaseauth
    • Packaging: Jar
    • Java: 17
  3. Add Dependencies:
    • Spring Web
    • Spring Security
    • Thymeleaf
    • Spring Data JPA
    • MySQL Driver
    • Lombok
  4. Generate the Project: Click on the Generate button to download the project as a zip file.
  5. Extract the Zip File: Extract the zip file to your preferred location.

Using an IDE

  1. Open Your IDE: Open your preferred IDE (IntelliJ IDEA, Eclipse, etc.).
  2. Import the Project: Import the extracted project as a Maven project.

Step 2: Add Maven Dependencies

Ensure your pom.xml contains the necessary dependencies. It should look something like this:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> 

Step 3: Configure MySQL Database

Create a Database

Create a database in your MySQL server using the following command:

create database login_system; 

Configure Database Properties

Add the following properties to the src/main/resources/application.properties file:

spring.datasource.url=jdbc:mysql://localhost:3306/login_system spring.datasource.username=root spring.datasource.password=root # Hibernate ddl auto (create, create-drop, validate, update) spring.jpa.hibernate.ddl-auto=update logging.level.org.springframework.security=DEBUG 

Step 4: Create JPA Entities

User Entity

Create a User class under the com.rameshfadatare.springsecuritydatabaseauth.model package:

package com.rameshfadatare.springsecuritydatabaseauth.model; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.util.Set; @Setter @Getter @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long 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(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id") ) private Set<Role> roles; } 

Role Entity

Create a Role class under the com.rameshfadatare.springsecuritydatabaseauth.model package:

package com.rameshfadatare.springsecuritydatabaseauth.model; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "roles") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; } 

Step 5: Create Repositories

UserRepository

Create a UserRepository interface under the com.rameshfadatare.springsecuritydatabaseauth.repository package:

package com.rameshfadatare.springsecuritydatabaseauth.repository; import com.rameshfadatare.springsecuritydatabaseauth.model.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); Boolean existsByEmail(String email); Optional<User> findByUsernameOrEmail(String username, String email); boolean existsByUsername(String username); } 

RoleRepository

Create a RoleRepository interface under the com.rameshfadatare.springsecuritydatabaseauth.repository package:

package com.rameshfadatare.springsecuritydatabaseauth.repository; import com.rameshfadatare.springsecuritydatabaseauth.model.Role; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface RoleRepository extends JpaRepository<Role, Long> { Optional<Role> findByName(String name); } 

Step 6: Create Custom UserDetailsService

Create a CustomUserDetailsService class under the com.rameshfadatare.springsecuritydatabaseauth.service package:

package com.rameshfadatare.springsecuritydatabaseauth.service; import com.rameshfadatare.springsecuritydatabaseauth.model.User; import com.rameshfadatare.springsecuritydatabaseauth.repository.UserRepository; import lombok.AllArgsConstructor; 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 java.util.Set; import java.util.stream.Collectors; @Service @AllArgsConstructor public class CustomUserDetailsService implements UserDetailsService { private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException { User user = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail) .orElseThrow(() -> new UsernameNotFoundException("User not exists by Username or Email")); Set<GrantedAuthority> authorities = user.getRoles().stream() .map((role) -> new SimpleGrantedAuthority(role.getName())) .collect(Collectors.toSet()); return new org.springframework.security.core.userdetails.User( usernameOrEmail, user.getPassword(), authorities ); } } 

Step 7: Spring Security Configuration

Create a SpringSecurityConfig class under the com.rameshfadatare.springsecuritydatabaseauth.config package:

package com.rameshfadatare.springsecuritydatabaseauth.config; import lombok.AllArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.userdetails.UserDetailsService; 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 @AllArgsConstructor public class SpringSecurityConfig { private UserDetailsService userDetailsService; @Bean public static PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated() ).formLogin( form -> form .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessUrl("/welcome") .permitAll() ).logout( logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .permitAll() ); return http.build(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { return configuration.getAuthenticationManager(); } } 

Step 8: Create Thymeleaf Templates

Login Page – login.html

Under the /src/main/resources/templates folder, create a login.html file and add the following content:

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Login System</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" th:href="@{/index}">Spring Security Custom Login Example</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 Email 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 Form</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"> Email</label> <input type="text" id="username" name="username" class="form-control" placeholder="Enter email address"/> </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">Submit</button> </div> </form> </div> </div> </div> </div> </div> </body> </html> 

Welcome Page – welcome.html

Under the /src/main/resources/templates folder, create a welcome.html file and add the following content:

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" > <head> <meta charset="UTF-8"> <title>Registration and Login System</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" th:href="@{/index}">Spring Security Custom Login Example</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 /> <div class="container"> <div class="row"> <h1> Welcome to Spring Security world!</h1> </div> </div> </body> </html> 

Step 9: Create Spring MVC Controller

Create a WelComeController class under the com.rameshfadatare.springsecuritydatabaseauth.controller package:

package com.rameshfadatare.springsecuritydatabaseauth.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class WelComeController { @GetMapping("/welcome") public String greeting() { return "welcome"; } @GetMapping("/login") public String login() { return "login"; } } 

Step 10: Insert SQL Scripts

Before testing Spring Security, use the following SQL scripts to insert data into the respective tables:

INSERT INTO users VALUES (1,'ramesh@gmail.com','ramesh','$2a$10$5PiyN0MsG0y886d8xWXtwuLXK0Y7zZwcN5xm82b4oDSVr7yF0O6em','ramesh'), (2,'admin@gmail.com','admin','$2a$10$gqHrslMttQWSsDSVRTK1OehkkBiXsJ/a4z2OURU./dizwOQu5Lovu','admin'); INSERT INTO roles VALUES (1,'ROLE_ADMIN'),(2,'ROLE_USER'); INSERT INTO users_roles VALUES (2,1),(1,2); 

Hibernate will automatically create the database tables, so you don’t need to create the tables manually.

Step 11: Run the Application

  1. Run the Application: Use your IDE to run the SpringSecuritDatabaseAuthApplication class.
  2. Access the Application: Open your browser and go to http://localhost:8080. You should see the custom login page.

Step 12: Test the Custom Login Page

  1. Navigate to the Login Page: Enter http://localhost:8080 in the browser.
  2. Login: Enter a username as admin and password as admin, then click the Submit button. Spring Boot Security Database Authentication Example
  3. After a successful login, you will see the welcome page. Spring Boot Security Database Authentication Example

Built-In Logout Feature

  1. Click on the logout button in the application to log out.

Conclusion

In this Spring Security tutorial, we learned how to implement a custom login form with database authentication using Spring Security and a MySQL database.

Leave a Comment

Scroll to Top