Spring Boot Security App

[0] Recommended tools
[0.1] Install PowerShell 7
[0.2] Install Microsoft OpenJDK
[0.3] Install Docker (v.4.24.2)
[0.4] Install Visual Code (x64 v.1.92.2)
[0] Create root directory for all projects
In home directory, create a project root directory.
In home directory, create a project root directory.
cd ~
.
mkdir SpringBootSecurity
.
cd SpringBootSecurity
.
[1] WorkgroupApp project
[1.1] Create project directory.
mkdir WorkgroupApp
.
cd WorkgroupApp
[1.2] Extract Spring Boot startup project.
Download spring boot demo project from
Unzip to ~\SpringBootSecurity\WorkgroupApp
[1.3] Configure the H2 Database
Add the following codes to application.properties
# H2 Database Configuration
spring.h2.console.enabled=true
spring.h2.console.settings.web-allow-others=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
Full code:
File → ~\SpringBootSecurity\WorkgroupApp\src\main\resources\application.properties
spring.application.name=demo
# H2 Database Configuration
spring.h2.console.enabled=true
spring.h2.console.settings.web-allow-others=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
[1.4] Create User Entity (Model)
Create a User
entity with fields for username, password, and roles.
File →
~\SpringBootSecurity\WorkgroupApp\src\main\java\com\example\demo\model\User.java
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import jakarta.persistence.*;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@ElementCollection(fetch = FetchType.EAGER)
private List<String> roles;
}
[1.5] Create User Repository
Create a repository interface for User entity.
File →
~\SpringBootSecurity\WorkgroupApp\src\main\java\com\example\demo\repository\UserRepository.java
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
[1.6] Configure Spring Security
Create a security configuration class.
package com.example.demo.security;
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.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
[1.7] Create JWT Utility
Create a utility class for generating and validating JWT tokens.
package com.example.demo.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtil {
private String secretKey = "your_secret_key"; // Use a strong key in production
private long validity = 3600000; // 1 hour
public String generateToken(String username) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, username);
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + validity))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
public boolean validateToken(String token, String username) {
final String extractedUsername = extractUsername(token);
return (extractedUsername.equals(username) && !isTokenExpired(token));
}
public String extractUsername(String token) {
return extractAllClaims(token).getSubject();
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
}
private boolean isTokenExpired(String token) {
return extractAllClaims(token).getExpiration().before(new Date());
}
}
[1.8] Create Authentication Controller
Create a controller to handle authentication requests.
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@PostMapping("/login")
public String login(@RequestBody AuthRequest authRequest) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
);
final UserDetails userDetails = userDetailsService.loadUserByUsername(authRequest.getUsername());
return jwtUtil.generateToken(userDetails.getUsername());
}
}
[1.9] Create AuthRequest DTO
Create a simple DTO for login requests.
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AuthRequest {
private String username;
private String password;
}
[1.10] Initializing Sample Users (Optional)
Populate the H2 database with a sample user on startup.
package com.example.demo.initializer;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class DataInitializer implements CommandLineRunner {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public DataInitializer(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public void run(String... args) throws Exception {
User user = new User();
user.setUsername("user");
user.setPassword(passwordEncoder.encode("password"));
user.setRoles(Arrays.asList("ROLE_USER"));
userRepository.save(user);
}
}
[1.4] Build Spring Boot Application
.\mvnw clean package
[1.5] Define Docker image (Dockerfile)
File → ~\RestfulServiceWithH2DB\EmployeeListApp\Dockerfile
# Use a base image with OpenJDK 17
FROM openjdk:17-slim
# Set the working directory
WORKDIR /app
# Copy the jar file into the container
COPY target/demo-0.0.1-SNAPSHOT.jar demo.jar
# Expose the port the app runs on
EXPOSE 8080
# Command to run the jar
CMD ["java", "-jar", "demo.jar"]
[1.6] Build Docker image (execute Dockerfile)
docker build -t myapp .
[1.7] Run Docker container
docker run -p 8080:8080 myapp
[1.8] Test REST API using Postman
Subscribe to my newsletter
Read articles from Mohamad Mahmood directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Mohamad Mahmood
Mohamad Mahmood
Mohamad's interest is in Programming (Mobile, Web, Database and Machine Learning). He studies at the Center For Artificial Intelligence Technology (CAIT), Universiti Kebangsaan Malaysia (UKM).