DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Component Tests for Spring Cloud Microservices
  • How To Implement OAuth2 Security in Microservices
  • A New Era Of Spring Cloud
  • Preserving Context Across Threads

Trending

  • Building a Real-Time Change Data Capture Pipeline With Debezium, Kafka, and PostgreSQL
  • Web Crawling for RAG With Crawl4AI
  • Enhancing Business Decision-Making Through Advanced Data Visualization Techniques
  • Can You Run a MariaDB Cluster on a $150 Kubernetes Lab? I Gave It a Shot
  1. DZone
  2. Coding
  3. Java
  4. Build J2EE Microservices Architecture

Build J2EE Microservices Architecture

This post will cover the following aspects: Keycloak setup, Eureka service registration and discovery, Spring Cloud API gateway, and more!

By 
Kunkka Li user avatar
Kunkka Li
·
Oct. 15, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
7.4K Views

Join the DZone community and get the full member experience.

Join For Free

I posted an article in regards to a single-page application(UI), but in this post, I'm going to introduce how to build microservice architecture for the J2EE application with Spring framework and open-source SSO framework Keycloak. This post will cover the following aspects:

  • Keycloak setup
  • Eureka service registration and discovery
  • Spring Cloud API gateway
  • Spring Security (OAuth2 login) and the integration with Keycloak
  • Microservices

The code is available in my Github and please check the docker-compose.yml at first so that you can read the rest of the post easier. One thing I need to mention here is you need to replace the IP address of the keycloak server URL with your own before running the docker containers.

YAML
 




xxxxxxxxxx
1
79


 
1
version: '3.4'
2
services:
3
  api-gateway:
4
    build:
5
      context: ./api-gateway
6
    ports:
7
      - "8080:8080"
8
    restart: on-failure
9
    environment:
10
      #overriding spring application.properties
11
      - eureka.client.serviceUrl.defaultZone=http://eureka-server:9091/eureka/
12
      - keycloak-client.server-url=http://10.0.0.17:18080/auth # use host name or ip of the host machine
13
    depends_on:
14
      - eureka-server
15
  eureka-server:
16
    build:
17
      context: ./eureka-server
18
    ports:
19
      - "9091:9091"
20
    restart: on-failure
21
  microservice-consumer:
22
    build:
23
      context: ./microservice-consumer
24
    ports:
25
      - "9080:9080"
26
    restart: on-failure
27
    environment:
28
      #overriding spring application.properties
29
      - eureka.client.serviceUrl.defaultZone=http://eureka-server:9091/eureka/
30
      - keycloak-client.server-url=http://10.0.0.17:18080/auth # use host name or ip of the host machine
31
    depends_on:
32
      - eureka-server
33
  microservice-producer:
34
    build:
35
      context: ./microservice-producer
36
    ports:
37
      - "9081:9081"
38
    restart: on-failure
39
    environment:
40
      #overriding spring application.properties
41
      - eureka.client.serviceUrl.defaultZone=http://eureka-server:9091/eureka/
42
      - keycloak-client.server-url=http://10.0.0.17:18080/auth # use host name or ip of the host machine
43
    depends_on:
44
      - eureka-server
45
  keycloak:
46
    image: jboss/keycloak:11.0.0
47
      volumes:
48
      - ./keycloak-server/realm-export.json:/tmp/keycloak/config/realm-export.json
49
    environment:
50
        KEYCLOAK_USER: admin
51
        KEYCLOAK_PASSWORD: admin
52
        KEYCLOAK_IMPORT: /tmp/keycloak/config/realm-export.json
53
        DB_VENDOR: POSTGRES
54
        DB_ADDR: postgres
55
        DB_DATABASE: keycloak
56
        DB_USER: keycloak
57
        DB_SCHEMA: public
58
        DB_PASSWORD: password
59
    ports:
60
      - "18080:18080"
61
    command:
62
      - "-b"
63
      - "0.0.0.0"
64
      - "-Djboss.socket.binding.port-offset=10000"
65
    restart: on-failure
66
    depends_on:
67
      - postgres
68
  postgres:
69
      image: postgres
70
      volumes:
71
        - postgres_data:/var/lib/postgresql/data
72
      environment:
73
        POSTGRES_DB: keycloak
74
        POSTGRES_USER: keycloak
75
        POSTGRES_PASSWORD: password
76
volumes:
77
    postgres_data:
78
      name: keycloak_postgres_data
79
      driver: local



Then, you can run the following cmd to start up docker containers.

Shell
 




xxxxxxxxxx
1


 
1
docker-compose up --build



1. Keycloak

Keycloak is an open-source identity and access management solution. It's convenient to integrate with Spring Security OAuth2 framework. Here I'm showing step by step how to set up a keycloak server. 

First of all, based on the docker-compose profile above, please use the following cmd to build and start a keycloak server. I have exported a JSON file(realm-export.json) that can be consumed by the keycloak docker container so that you don't need to configure step by step. Anyway, I will show that steps one by one.
Shell
 




x


 
1
docker-compose up --build keycloak



1.1 Create a Realm

Login http://localhost:18080/ with admin/admin, then create a realm as below, leaving all the fields as default.

spring-micro-main


1.2 Create Clients Under the Above Realm

clients

As shown above, we created three clients that represent API-gateway, microservice consumer, microservice producer. There are two things necessary to mention.

First, fill mandatory field(Valid Redirect URIs) as * so that we can redirect back to our URI configured in our application.

Then, choose client id and secrete as Client Authenticator, which is suitable for the integration with  Spring Security OAuth2 client.

spring-micro-gateway


1.3 Create a User

As shown in the screenshot below, we need to fill some necessary fields like first name, last name, and email, etc.

keycloak


2. Eureka Sever — Service Registration

It's quite straight forward to build a service registration server based on Spring Cloud Eureka, and we just need annotation @EnableEurekaServer to enable that.

3. API Gateway

Spring framework 5 releases Spring Cloud gateway to replace the previous gateway — Spring Cloud Zuul. Spring Cloud Gateway is a new generation nonblocking gateway built on top of Project Reactor, Spring WebFlux, and Spring Boot 2.0, while Zuul is a blocking gateway.  So, in this post, I use Spring Cloud Gateway as an API gateway for the microservices.

First of all, I need to show the application.yml configuration profile.

YAML
 




xxxxxxxxxx
1
60


 
1
logging:
2
  level:
3
    root: WARN
4
    org.springframework.web: INFO
5
    org.springframework.security: DEBUG
6
    org.springframework.security.oauth2: DEBUG
7

          
8
server:
9
  port: 8080
10
keycloak-client:
11
  server-url: http://localhost:18080/auth
12
  realm:  spring-micro-main
13
spring:
14
  application:
15
    name: api-gateway
16
  security:
17
    oauth2:
18
      client:
19
        registration:
20
          keycloak:
21
            provider: keycloak
22
            client-id: spring-micro-gateway
23
            client-secret: 756b0558-018b-4809-b478-bd5b4995d325
24
            authorization-grant-type: authorization_code
25
            redirect-uri: http://localhost:8080/login/oauth2/code/keycloak
26
            scope: openid
27
        provider:
28
          keycloak:
29
            authorization-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/auth
30
            token-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/token
31
            user-info-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/userinfo
32
            jwk-set-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/certs
33
            user-name-attribute: name
34
            user-info-authentication-method: header
35
      resourceserver:
36
        jwt:
37
          jwk-set-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/certs
38
  cloud:
39
    gateway:
40
      routes:
41
        - id: microservice-consumer
42
          uri: lb://microservice-consumer
43
          predicates:
44
            - Path=/api/consume/**
45
          filters:
46
            - TokenRelay=
47
            - RemoveRequestHeader=Cookie
48
        - id: microservice-producer
49
          uri: lb://microservice-producer
50
          predicates:
51
            - Path=/api/produce/**
52
          filters:
53
            - TokenRelay=
54
            - RemoveRequestHeader=Cookie
55

          
56
eureka:
57
  client:
58
    serviceUrl:
59
      defaultZone: http://localhost:9091/eureka/
60

          



3.1 Route Definition in Spring Cloud Gateway

We defined two routes for two microservices: consumer and producer. The lb://microservice-consumer means it points to microservice-consumer based on service registration server - Eureka. We use TokenRelay so that the access_token from the request can be passed through to the microservice resource server which is secured by Spring Security OAuth2 along with Keycloak as well.

3.2 Eureka Client Configuration

The API gateway also acts as a Eureka client so that it can work with microservice replicas. We just need an annotation @EnableEurekaClient and configure the eureka server URL in the properties.

YAML
 




xxxxxxxxxx
1


 
1
eureka:
2
  client:
3
    serviceUrl:
4
      defaultZone: http://localhost:9091/eureka/



3.3 Spring Security OAuth2 and the Integration With Keycloak Server

3.3.1 Spring Security OAuth2 

One of the key features of Spring Security 5 is the native support for OAuth2 and OIDC, instead of the legacy client support in the old Spring Security OAuth subproject, integrating with IAM(Identity and Access Management) providers gets super easy. We need to add the following dependencies:

XML
 




x


 
1
<dependency>
2
  <groupId>org.springframework.boot</groupId>
3
  <artifactId>spring-boot-starter-oauth2-client</artifactId>
4
</dependency>
5
<dependency>
6
  <groupId>org.springframework.cloud</groupId>
7
  <artifactId>spring-cloud-starter-security</artifactId>
8
</dependency>



3.3.2 OAuth2 Client Registration

The properties for OAuth 2 clients are prefixed with spring.security.oauth2.client.registration andspring.security.

oauth2.client.provider. For Keycloak specifically, we have to configure the details of the OAuth2 provider and provides the details of client registration as below.

YAML
 




x


 
1
spring:
2
  security:
3
    oauth2:
4
      client:
5
        registration:
6
          keycloak:
7
            provider: keycloak
8
            client-id: spring-micro-consumer
9
            client-secret: b2678444-3e56-466d-b035-a6109ca686ca
10
            authorization-grant-type: authorization_code
11
            redirect-uri: http://localhost:9080/login/oauth2/code/keycloak
12
            scope: openid
13
        provider:
14
          keycloak:
15
            authorization-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/auth
16
            token-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/token
17
            user-info-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/userinfo
18
            jwk-set-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/certs
19
            user-name-attribute: name
20
            user-info-authentication-method: header
21
      resourceserver:
22
        jwt:
23
          jwk-set-uri: ${keycloak-client.server-url}/realms/${keycloak-client.realm}/protocol/openid-connect/certs



3.3.3 Spring Security OAuth2 Resource Server

Keycloak uses a public/private key pair to issue and verify the JWT(JSON Web Token). In particular, it uses a private key to sign the access token, and the OAuth2 client uses the public key to verify the token. 

We need to protect the API gateway as an OAuth2 resource server so that when a request coming in with a bearer token under the Authorization header, it can also verify the token rather than redirect to the SSO server for authentication, then the request can eventually go to downstream microservices. For example, we can use an HTTP client to issue a request as below.

HTTP
 




xxxxxxxxxx
1


 
1
GET localhost:8080/api/produce/
2
Authorization: Bearer <your access token>



3.3.4 Enable OAuth2 Login and Resource Server

To enable Spring Security OAuth2 login as well as a resource server, we need to leverage DSL methods.

Spring Security’s OAuth 2.0 Login support is enabled via the Spring Security oauth2Login() DSL method.

Spring Security’s Resource Server support is enabled via the Spring Security oauth2ResourceServer DSL method.

Illustrated as below:

Java
 




xxxxxxxxxx
1
19


 
1
@EnableWebFluxSecurity
2
@EnableReactiveMethodSecurity
3
public class SpringSecurityConfig {
4

          
5
    @Bean
6
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
7
        // @formatter:off
8
        http
9
                .authorizeExchange()
10
                .anyExchange().authenticated()
11
                .and()
12
                .oauth2Login()
13
                .and()
14
                .oauth2ResourceServer()
15
                .jwt();
16
        return http.build();
17
        // @formatter:on
18
    }
19
}



4. Microservices

Microservices should be protected by Keycloak and enabled as the OAuth2 resource server as well. So the configuration is similar to the API gateway. One key difference is that Spring Cloud gateway is built on top of Spring WebFlux while our microservices are built on top of Spring MVC. So the security configuration has a slight difference, illustrated as below.

Java
 




xxxxxxxxxx
1
14


 
1
@Configuration
2
public class OAuth2ResourceServerConfig extends WebSecurityConfigurerAdapter {
3

          
4
    @Override
5
    protected void configure(HttpSecurity http) throws Exception {
6
        http.authorizeRequests()
7
                .anyRequest().authenticated()
8
                .and()
9
                .oauth2Login()
10
                .and()
11
                .oauth2ResourceServer()
12
                .jwt();
13
    }
14
}



That's it and you are good to go. Please check the source code from my Github.

Spring Framework Spring Security microservice Spring Cloud Build (game engine) Architecture

Published at DZone with permission of Kunkka Li. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Component Tests for Spring Cloud Microservices
  • How To Implement OAuth2 Security in Microservices
  • A New Era Of Spring Cloud
  • Preserving Context Across Threads

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!