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