This tutorial will set up a basic Spring Boot application, configure Spring Security for database authentication, and secure REST endpoints.
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)
Project Structure
Your project structure should look like this:
Step 2: Adding Dependencies
Add the necessary dependencies for Spring Boot, Spring Security, and H2 database in the pom.xml
file.
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-security-example</artifactId>
<version>1.0-SNAPSHOT</version>
<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>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 3: Configuring Spring Security
Create Security Configuration
Create a configuration class SecurityConfig
to set up Spring Security with database authentication.
package com.example.security.config;
import com.example.security.service.UserService;
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.config.annotation.web.configuration.EnableWebSecurity;
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;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final UserService userService;
public SecurityConfig(UserService userService) {
this.userService = userService;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/api/public/**").permitAll() // Public endpoints
.anyRequest().authenticated() // Secure all other endpoints
)
.httpBasic(); // Basic authentication
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return userService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Step 4: Creating the Entity Class
Create an Entity
class User
in the com.example.security.model
package.
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 Repository Interface
Create a repository interface for the User
entity.
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 Service Class
Create a service class to handle business logic for user-related operations and implement the UserDetailsService
interface.
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.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return org.springframework.security.core.userdetails.User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
public User save(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
}
Step 7: Creating the Main Application Class
Create the main application class to run your Spring Boot application.
package com.example.security;
import com.example.security.model.User;
import com.example.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringSecurityExampleApplication implements CommandLineRunner {
@Autowired
private UserService userService;
public static void main(String[] args) {
SpringApplication.run(SpringSecurityExampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// Create a default user and admin
User user = new User();
user.setUsername("user");
user.setPassword("password");
user.setRole("USER");
userService.save(user);
User admin = new User();
admin.setUsername("admin");
admin.setPassword("password");
admin.setRole("ADMIN");
userService.save(admin);
}
}
Step 8: Creating REST Controllers
Create REST controllers to expose endpoints. Define some endpoints as public and others as secured.
PublicController.java
package com.example.security.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/public")
public class PublicController {
@GetMapping("/welcome")
public String welcome() {
return "Welcome to the public API!";
}
}
PrivateController.java
package com.example.security.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/private")
public class PrivateController {
@GetMapping("/hello")
public String hello() {
return "Hello, secured API!";
}
}
Step 9: Configuring Application Properties
Configure your application properties to set up the H2 database.
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
Step 10: Running the Application
Run your Spring Boot application and test the endpoints. You can use tools like Postman or cURL to interact with the REST API.
Example Requests
-
Public endpoint (no authentication required):
GET /api/public/welcome
-
Secured endpoint (authentication required):
GET /api/private/hello
Use basic authentication with username
user
and passwordpassword
(oradmin
for admin access).
Conclusion
In this tutorial, we integrated Spring Security 6 with Spring Boot 3 using database authentication. We configured Spring Security to secure REST endpoints with basic authentication, created a simple user service, and set up public and secured endpoints. This approach can be extended to include more complex authentication mechanisms as needed.
Comments
Post a Comment