Skip to main content

Command Palette

Search for a command to run...

Spring Boot Security App

Published
4 min read
M

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.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