Spring Boot Security App
Mohamad's interest is in Programming (Mobile, Web, Database and Machine Learning). He is studying at the Center For Artificial Intelligence Technology (CAIT), Universiti Kebangsaan Malaysia (UKM).
[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