What is Form-Based Authentication?
Form-based authentication is a popular method in which users are required to log in through a web login form. Upon successful authentication, users are granted access to protected resources. This method allows for a customizable user experience, as the login form can be styled and designed to match the look and feel of the application.
Prerequisites
Before we start, ensure you have the following:
- Java Development Kit (JDK) installed
- Apache Maven installed
- An IDE (Integrated Development Environment) like IntelliJ IDEA or Eclipse
Step 1: Setting Up the Project
Create a Spring Boot Project
- Open your IDE and create a new Spring Boot project using Spring Initializr.
- Add the following dependencies:
- Spring Web
- Spring Security
- Spring Data JPA
- H2 Database (for simplicity, but you can use any database of your choice)
- Spring Boot Starter Thymeleaf (for creating simple views)
Project Structure
Your project structure should look like this:
spring-security-form-based-auth
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── security
│ │ │ ├── SecurityConfig.java
│ │ │ ├── SecurityApplication.java
│ │ │ ├── model
│ │ │ │ └── User.java
│ │ │ ├── repository
│ │ │ │ └── UserRepository.java
│ │ │ ├── service
│ │ │ │ └── UserService.java
│ │ │ └── controller
│ │ │ └── HomeController.java
│ ├── main
│ │ └── resources
│ │ ├── templates
│ │ │ ├── home.html
│ │ │ ├── login.html
│ │ └── application.properties
└── pom.xml
Step 2: Adding Dependencies
Add the necessary dependencies for Spring Security, Spring Data JPA, H2 database, and Thymeleaf in the pom.xml
file.
pom.xml
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Step 3: Configuring the Application Properties
Configure the application properties for the H2 database and other settings.
application.properties
# H2 Database configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
# JPA settings
spring.jpa.hibernate.ddl-auto=update
# Thymeleaf settings
spring.thymeleaf.cache=false
Step 4: Creating the User Entity
Create a User
entity in the com.example.security.model
package.
User.java
package com.example.security.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String role;
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
Step 5: Creating the User Repository
Create a UserRepository
interface in the com.example.security.repository
package.
UserRepository.java
package com.example.security.repository;
import com.example.security.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
Step 6: Creating the User Service
Create a UserService
class in the com.example.security.service
package.
UserService.java
package com.example.security.service;
import com.example.security.model.User;
import com.example.security.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.HashSet;
@Service
public class UserService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@PostConstruct
public void init() {
User admin = new User();
admin.setUsername("admin");
admin.setPassword(passwordEncoder.encode("admin"));
admin.setRole("ADMIN");
userRepository.save(admin);
User user = new User();
user.setUsername("user");
user.setPassword(passwordEncoder.encode("password"));
user.setRole("USER");
userRepository.save(user);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
com.example.security.model.User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
Step 7: Configuring Spring Security
Create a SecurityConfig
class in the com.example.security
package to configure Spring Security for form-based authentication.
SecurityConfig.java
package com.example.security;
import com.example.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private UserService userService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/h2-console/**").permitAll() // Allow access to H2
console
.requestMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin ->
formLogin
.loginPage("/login")
.permitAll()
.defaultSuccessUrl("/home", true)
)
.logout(logout ->
logout.permitAll()
);
// Disable CSRF and frame options for H2 console
http.csrf().disable();
http.headers().frameOptions().disable();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
}
Step 8: Creating the Home Controller
Create a HomeController
class in the com.example.security.controller
package.
HomeController.java
package com.example.security.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String root() {
return "index";
}
@GetMapping("/home")
public String home() {
return "home";
}
@GetMapping("/login")
public String login() {
return "login";
}
}
Step 9: Creating the Views
Create simple HTML views for the home page, login page, and index page in the src/main/resources/templates
directory.
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome to the Home Page!</h1>
<div>
<a href="/logout" th:href="@{/logout}">Logout</a>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form th:action="@{/login}" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<button type="submit">Login</button>
</div>
</form>
</body>
</html>
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Index</title>
</head>
<body>
<h1>Welcome to the Application!</h1>
<div>
<a href="/login" th:href="@{/login}">Login</a>
</div>
</body>
</html>
Step 10: Creating the Main Application Class
Create the main application class to run your Spring Boot application.
SecurityApplication.java
package com.example.security;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class, args);
}
}
Step 11: Running the Application
To run the application, execute the SecurityApplication
class. This will start the Spring Boot application with Spring Security configured for form-based authentication.
Accessing the Application
- Open your browser and navigate to
http://localhost:8080/h2-console
to access the H2 database console. Use the JDBC URLjdbc:h2:mem:testdb
, usernamesa
, and an empty password to log in. - Navigate to
http://localhost:8080/
to access the index page. - Navigate to
http://localhost:8080/login
to access the login page. Use the credentials defined in yourUserService
:username: admin
password: admin
username: user
password: password
After logging in, you will be redirected to the home page.
Conclusion
In this tutorial, we have walked through setting up a basic Spring Boot application and integrating it with Spring Security for form-based authentication. We configured Spring Security to secure our application with a custom login form and created a simple web application with Thymeleaf views. By following this tutorial, you should now have a good understanding of how to integrate Spring Security with Spring Boot and secure your web applications using form-based authentication.
Comments
Post a Comment