Prerequisites
Before we start, ensure you have the following:
- Java Development Kit (JDK) installed
- Apache Maven installed
- Docker installed
- Docker Compose installed
- An IDE (such as IntelliJ IDEA, Eclipse, or VS Code) installed
Overview of the Microservices
We will create three Spring Boot microservices:
- Employee Service: Manages employee information.
- Department Service: Manages department information.
- API Gateway: Routes requests and handles security with Keycloak.
We will also set up Keycloak as our identity provider.
Step 1: Setting Up Keycloak
1.1 Run Keycloak with Docker
Create a docker-compose.yml
file to run Keycloak:
version: '3'
services:
keycloak:
image: quay.io/keycloak/keycloak:latest
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
command: start-dev
ports:
- "8080:8080"
Run the following command to start Keycloak:
docker-compose up -d
1.2 Configure Keycloak
-
Access Keycloak Admin Console:
- Open your web browser and go to
http://localhost:8080
. - Log in with the username
admin
and passwordadmin
.
- Open your web browser and go to
-
Create a Realm:
- Click on the
Master
drop-down on the top left corner and selectCreate Realm
. - Name the realm
springboot
.
- Click on the
-
Create a Client:
- In the
springboot
realm, go toClients
and clickCreate
. - Name the client
springboot-client
and set the client type toOpenID Connect
. - Set the Root URL to
http://localhost:8080
and clickSave
. - In the
Settings
tab, setAccess Type
toconfidential
and setService Accounts Enabled
toON
. - Copy the
Client Secret
from theCredentials
tab.
- In the
-
Create a Role:
- Go to
Roles
and clickAdd Role
. - Name the role
user
and clickSave
.
- Go to
-
Create a User:
- Go to
Users
and clickAdd User
. - Set the username to
testuser
and clickSave
. - In the
Credentials
tab, set a password and turn offTemporary
. - In the
Role Mappings
tab, assign theuser
role to the user.
- Go to
Step 2: Create the Employee Service
2.1 Create a Spring Boot Project
-
Open Spring Initializr:
- Go to Spring Initializr in your web browser.
-
Configure Project Metadata:
- Project: Maven Project
- Language: Java
- Spring Boot: Select the latest version of Spring Boot 3.2
- Group: com.example
- Artifact: employee-service
- Name: employee-service
- Description: Employee Service
- Package Name: com.example.employeeservice
- Packaging: Jar
- Java Version: 17 (or your preferred version)
- Click
Next
.
-
Select Dependencies:
- On the
Dependencies
screen, select the dependencies you need:- Spring Web
- Spring Data JPA
- Spring Security
- Keycloak Spring Boot Starter
- H2 Database
- Click
Next
.
- On the
-
Generate the Project:
- Click
Generate
to download the project zip file. - Extract the zip file to your desired location.
- Click
-
Open the Project in Your IDE:
- Open your IDE and import the project as a Maven project.
2.2 Update application.properties
Open the application.properties
file located in the src/main/resources
directory and add the following configuration:
server.port=8081
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.jpa.hibernate.ddl-auto=update
keycloak.realm=springboot
keycloak.auth-server-url=http://localhost:8080
keycloak.resource=springboot-client
keycloak.credentials.secret=YOUR_CLIENT_SECRET
keycloak.bearer-only=true
keycloak.security-constraints[0].authRoles[0]=user
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/employees/*
Replace YOUR_CLIENT_SECRET
with the client secret you copied from the Keycloak admin console.
2.3 Create Employee Entity
Create an Employee
entity class in the com.example.employeeservice.model
package:
package com.example.employeeservice.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String department;
// Getters and Setters
}
2.4 Create Employee Repository
Create an EmployeeRepository
interface in the com.example.employeeservice.repository
package:
package com.example.employeeservice.repository;
import com.example.employeeservice.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
2.5 Create Employee Controller
Create an EmployeeController
class in the com.example.employeeservice.controller
package:
package com.example.employeeservice.controller;
import com.example.employeeservice.model.Employee;
import com.example.employeeservice.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private final EmployeeRepository employeeRepository;
@Autowired
public EmployeeController(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@GetMapping
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@PostMapping
public Employee createEmployee(@RequestBody Employee employee) {
return employeeRepository.save(employee);
}
}
2.6 Create Security Configuration
Create a SecurityConfig
class in the com.example.employeeservice.config
package:
package com.example.employeeservice.config;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
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.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/employees/*").hasRole("user")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
return http.build();
}
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SimpleAuthorityMapper grantedAuthorityMapper() {
return new SimpleAuthorityMapper();
}
}
Step 3: Create the Department Service
3.1 Create a Spring Boot Project
-
Open Spring Initializr:
- Go to Spring Initializr in your web browser.
-
Configure Project Metadata:
- Project: Maven Project
- Language: Java
- Spring Boot: Select the latest version of Spring Boot 3.2
- Group: com.example
- Artifact: department-service
- Name: department-service
- Description: Department Service
- Package Name: com.example.departmentservice
- Packaging: Jar
- Java Version: 17 (or your preferred version)
- Click
Next
.
-
Select Dependencies:
- On the
Dependencies
screen, select the dependencies you need:- Spring Web
- Spring Data JPA
- Spring Security
- Keycloak Spring Boot Starter
- H2 Database
- Click `Next
- On the
`.
-
Generate the Project:
- Click
Generate
to download the project zip file. - Extract the zip file to your desired location.
- Click
-
Open the Project in Your IDE:
- Open your IDE and import the project as a Maven project.
3.2 Update application.properties
Open the application.properties
file located in the src/main/resources
directory and add the following configuration:
server.port=8082
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.jpa.hibernate.ddl-auto=update
keycloak.realm=springboot
keycloak.auth-server-url=http://localhost:8080
keycloak.resource=springboot-client
keycloak.credentials.secret=YOUR_CLIENT_SECRET
keycloak.bearer-only=true
keycloak.security-constraints[0].authRoles[0]=user
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/departments/*
Replace YOUR_CLIENT_SECRET
with the client secret you copied from the Keycloak admin console.
3.3 Create Department Entity
Create a Department
entity class in the com.example.departmentservice.model
package:
package com.example.departmentservice.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
}
3.4 Create Department Repository
Create a DepartmentRepository
interface in the com.example.departmentservice.repository
package:
package com.example.departmentservice.repository;
import com.example.departmentservice.model.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DepartmentRepository extends JpaRepository<Department, Long> {
}
3.5 Create Department Controller
Create a DepartmentController
class in the com.example.departmentservice.controller
package:
package com.example.departmentservice.controller;
import com.example.departmentservice.model.Department;
import com.example.departmentservice.repository.DepartmentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/departments")
public class DepartmentController {
private final DepartmentRepository departmentRepository;
@Autowired
public DepartmentController(DepartmentRepository departmentRepository) {
this.departmentRepository = departmentRepository;
}
@GetMapping
public List<Department> getAllDepartments() {
return departmentRepository.findAll();
}
@PostMapping
public Department createDepartment(@RequestBody Department department) {
return departmentRepository.save(department);
}
}
3.6 Create Security Configuration
Create a SecurityConfig
class in the com.example.departmentservice.config
package:
package com.example.departmentservice.config;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
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.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/departments/*").hasRole("user")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
return http.build();
}
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SimpleAuthorityMapper grantedAuthorityMapper() {
return new SimpleAuthorityMapper();
}
}
Step 4: Create the API Gateway
4.1 Create a Spring Boot Project
-
Open Spring Initializr:
- Go to Spring Initializr in your web browser.
-
Configure Project Metadata:
- Project: Maven Project
- Language: Java
- Spring Boot: Select the latest version of Spring Boot 3.2
- Group: com.example
- Artifact: api-gateway
- Name: api-gateway
- Description: API Gateway
- Package Name: com.example.apigateway
- Packaging: Jar
- Java Version: 17 (or your preferred version)
- Click
Next
.
-
Select Dependencies:
- On the
Dependencies
screen, select the dependencies you need:- Spring Cloud Gateway
- Spring Security
- Keycloak Spring Boot Starter
- Click
Next
.
- On the
-
Generate the Project:
- Click
Generate
to download the project zip file. - Extract the zip file to your desired location.
- Click
-
Open the Project in Your IDE:
- Open your IDE and import the project as a Maven project.
4.2 Update application.yml
Create an application.yml
file in the src/main/resources
directory and configure it as follows:
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: employee_service
uri: http://localhost:8081
predicates:
- Path=/employees/**
- id: department_service
uri: http://localhost:8082
predicates:
- Path=/departments/**
keycloak:
realm: springboot
auth-server-url: http://localhost:8080
resource: springboot-client
credentials:
secret: YOUR_CLIENT_SECRET
bearer-only: true
Replace YOUR_CLIENT_SECRET
with the client secret you copied from the Keycloak admin console.
4.3 Create Security Configuration
Create a SecurityConfig
class in the com.example.apigateway.config
package:
package com.example.apigateway.config;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
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.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/employees/*", "/departments/*").hasRole("user")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
return http.build();
}
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SimpleAuthorityMapper grantedAuthorityMapper() {
return new SimpleAuthorityMapper();
}
}
Step 5: Running the Microservices
5.1 Running Authentication Service
- Open the
AuthServiceApplication
class in thesrc/main/java/com/example/authservice
directory. - Click the green
Run
button in your IDE or use the terminal to run the application:./mvnw spring-boot:run
5.2 Running Employee Service
- Open the
EmployeeServiceApplication
class in thesrc/main/java/com/example/employeeservice
directory. - Click the green
Run
button in your IDE or use the terminal to run the application:./mvnw spring-boot:run
5.3 Running Department Service
- Open the
DepartmentServiceApplication
class in thesrc/main/java/com/example/departmentservice
directory. - Click the green
Run
button in your IDE or use the terminal to run the application:./mvnw spring-boot:run
5.4 Running API Gateway
- Open the
ApiGatewayApplication
class in thesrc/main/java/com/example/apigateway
directory. - Click the green
Run
button in your IDE or use the terminal to run
the application:
./mvnw spring-boot:run
Step 6: Testing the Application
You can use tools like Postman to test the authentication and secure access to the microservices.
6.1 Get Access Token
- Create a new
POST
request tohttp://localhost:8080/realms/springboot/protocol/openid-connect/token
. - In the
Body
tab, selectx-www-form-urlencoded
and add the following parameters:client_id
:springboot-client
username
:testuser
password
:testpassword
grant_type
:password
client_secret
:YOUR_CLIENT_SECRET
- Send the request and copy the access token from the response.
6.2 Access Secured Employee Service
- Create a new
GET
request tohttp://localhost:8080/employees
. - Add the
Authorization
header with the valueBearer <ACCESS_TOKEN>
. - Send the request and verify that you receive the list of employees.
6.3 Access Secured Department Service
- Create a new
GET
request tohttp://localhost:8080/departments
. - Add the
Authorization
header with the valueBearer <ACCESS_TOKEN>
. - Send the request and verify that you receive the list of departments.
Conclusion
In this tutorial, we created a microservices architecture with Spring Boot and secured it using Keycloak. We built an authentication service to issue tokens, secured the employee and department services with Keycloak, and created an API Gateway to route and secure requests. This setup provides a solid foundation for developing secure microservices architectures.
Comments
Post a Comment