Skip to content

Commit

Permalink
Merge pull request #28 from tswlun002/feature/add-security-for-micros…
Browse files Browse the repository at this point in the history
…ervices

Feature/add security for microservices
  • Loading branch information
tswlun002 authored Jul 18, 2024
2 parents ab06ae7 + 1a0e404 commit f9aac3d
Show file tree
Hide file tree
Showing 16 changed files with 206 additions and 64 deletions.
4 changes: 4 additions & 0 deletions config-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-monitor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication {

public static void main(String[] args) {
Expand Down
18 changes: 14 additions & 4 deletions config-server/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,20 @@ spring:
properties:
topic:
replication-factor: 1


server:
port: 8071
eureka:
instance:
hostname: discoveryServerApp
preferIpAddress: true
client:
fetch-registry: true
register-with-eureka: true
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:8080/eureka/
healthcheck:
enabled: true
endpoints:
shutdown:
enabled: true
encrypt:
key: 7E93D539EAA5C42F8523AB1627D1B
management:
Expand Down
4 changes: 2 additions & 2 deletions config-server/src/main/resources/config/discoveryserver.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
server:
port: 8070
port: 8080
eureka:
instance:
hostname: discoveryServerApp
client:
fetch-registry: false
register-with-eureka: false
register-with-eureka: true
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
8 changes: 6 additions & 2 deletions config-server/src/main/resources/config/gatewayserver.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
server:
port: 8072
#spring:
# security:
# oauth2:
# resourceserver:
# jwt:
# jwk-set-uri: "http://keyClock:8080/realms/master/protocol/openid-connect/certs"
resilience4j.circuitbreaker:
configs:
default:
Expand Down
4 changes: 2 additions & 2 deletions discovery-server/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ spring:
application:
name: discoveryserver
config:
import: "configserver:http://configServerApp:8071/"
import: "configserver:http://configServerApp:8080/"
cloud:
config:
enabled: true
uri: "http://configServerApp:8071"
uri: "http://configServerApp:8080"
stream:
kafka:
binder:
Expand Down
25 changes: 15 additions & 10 deletions docker-compose-servers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ services:
context: ./config-server
image: pdf_editor_config:latest
container_name: configServerApp
ports:
- "8071:8071"
networks:
- server_net

Expand All @@ -21,8 +19,6 @@ services:
context: ./discovery-server
image: pdf_editor_discover:latest
container_name: discoveryServerApp
ports:
- "8070:8070"
depends_on:
- configServerApp
networks:
Expand All @@ -48,8 +44,6 @@ services:
context: ./document-service
image: pdf-editor-document:latest
container_name: documentsServerApp
ports:
- "8082:8082"
depends_on:
- configServerApp
- discoveryServerApp
Expand All @@ -64,8 +58,6 @@ services:
context: ./email-service
image: pdf-editor-email:latest
container_name: emailServerApp
ports:
- "8083:8083"
depends_on:
- configServerApp
- discoveryServerApp
Expand All @@ -79,13 +71,26 @@ services:
image: pdf-editor-user:latest
container_name: usersServerApp
hostname: usersServerApp
ports:
- "8080:8080"
depends_on:
- configServerApp
- discoveryServerApp
networks:
- server_net

#KEYCLOCK CONTAINER
keyClock:
image: quay.io/keycloak/keycloak:23.0.6
container_name: keyClock
hostname: keyClock
ports:
- "7080:8080"
networks:
- server_net
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
command:
- start-dev
networks:
server_net:
external: true
Expand Down
9 changes: 3 additions & 6 deletions document-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ spring:
application:
name: "documents"
config:
import: "configserver:http://configServerApp:8071/"
import: "configserver:http://configServerApp:8080/"
cloud:
config:
enabled: true
uri: "http://configServerApp:8071"
uri: "http://configServerApp:8080"
stream:
kafka:
binder:
Expand All @@ -29,9 +29,6 @@ spring:

topics:
download-document-name: download-document-event

server:
port: 8082
management:
endpoints:
web:
Expand All @@ -52,7 +49,7 @@ eureka:
fetch-registry: true
register-with-eureka: true
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:8070/eureka/
defaultZone: http://${eureka.instance.hostname}:8080/eureka/
healthcheck:
enabled: true
endpoints:
Expand Down
9 changes: 3 additions & 6 deletions email-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ spring:
application:
name: "email"
config:
import: "configserver:http://configServerApp:8071/"
import: "configserver:http://configServerApp:8080/"
jackson:
parser:
allow-unquoted-field-names: true
cloud:
config:
enabled: true
uri: http://configServerApp:8071
uri: http://configServerApp:8080
stream:
kafka:
binder:
Expand All @@ -30,9 +30,6 @@ spring:
topics:
retry: "download-document-event.RETRY"
dead: "download-document-event.DEAD"

server:
port: 8083
management:
endpoints:
web:
Expand All @@ -53,7 +50,7 @@ eureka:
fetch-registry: true
register-with-eureka: true
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:8070/eureka/
defaultZone: http://${eureka.instance.hostname}:8080/eureka/
healthcheck:
enabled: true
endpoints:
Expand Down
17 changes: 17 additions & 0 deletions gateway-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.gatewayserver.config;

import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class KeycloakRoleConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
@Override
public Collection<GrantedAuthority> convert(Jwt source) {
Map<String, List<String>> realmAccess = (Map<String, List<String>>) source.getClaims().get("realm_access");
if(realmAccess==null||realmAccess.isEmpty()){
return new ArrayList<>();
}
return realmAccess.get("roles")
.stream().map(roleName->new SimpleGrantedAuthority("ROLE_"+roleName))
.collect(Collectors.toList());

}

/*@Override
public <U> Converter<Jwt, U> andThen(Converter<? super Collection<GrantedAuthority>, ? extends U> after) {
return Converter.super.andThen(after);
}*/
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.gatewayserver.config;

public enum Roles {
CLIENT,
ADMIN
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,68 @@
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.Buildable;
import org.springframework.cloud.gateway.route.builder.PredicateSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

import java.time.Duration;
import java.util.function.Function;

@Configuration
public class RoutesConfig {



@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes().
route(predicateSpec -> predicateSpec.path("/pdf-editor/users/**").
filters(filterSpec->
{

return filterSpec.rewritePath("/pdf-editor/users/(?<segment>.*)", "/pdf-editor/users/${segment}")
filterSpec.rewritePath("/pdf-editor/users/(?<segment>.*)", "/pdf-editor/users/${segment}")
.circuitBreaker(circuitConfi ->
circuitConfi.setName("userServiceCircuitBreaker")
.setFallbackUri("/pdf-editor/fallback/contact-team")
);

})
.uri("lb://USERS"))
.route(predicateSpec -> predicateSpec.path("/pdf-editor/documents/**").
filters(filterSpec->filterSpec.rewritePath("/pdf-editor/documents/(?<segment>.*)","/pdf-editor/documents/${segment}")
.circuitBreaker(circuitConfi->
circuitConfi.setName("documentsCircuitBreaker")
.setFallbackUri("/pdf-editor/fallback/contact-team")
.addStatusCode(HttpStatus.SERVICE_UNAVAILABLE.name())
))
.uri("lb://DOCUMENTS"))
.route(predicateSpec -> predicateSpec.path("/pdf-editor/emails/**").
filters(filterSpec->filterSpec.rewritePath("/pdf-editor/emails/(?<segment>.*)","/pdf-editor/email/${segment}")
.circuitBreaker(circuitConfi->
circuitConfi.setName("emailCircuitBreaker")
.setFallbackUri("/pdf-editor/fallback/contact-team")
.addStatusCode(HttpStatus.SERVICE_UNAVAILABLE.name())
))
.uri("lb://EMAIL"))
)
).uri("lb://USERS"))
.route(
buildRoute("/pdf-editor/documents/**","/pdf-editor/documents/(?<segment>.*)",
"/pdf-editor/documents/${segment}","documentsCircuitBreaker"
,"/pdf-editor/fallback/contact-team","lb://DOCUMENTS")
)
.route(buildRoute("/pdf-editor/emails/**","/pdf-editor/emails/(?<segment>.*)",
"/pdf-editor/emails/${segment}","emailCircuitBreaker"
,"/pdf-editor/fallback/contact-team","lb://EMAILS")

)
.route(buildRoute("/pdf-editor/configserver/**","/pdf-editor/configserver/(?<segment>.*)",
"/${segment}","configServerCircuitBreaker"
,"/pdf-editor/fallback/contact-team","lb://CONFIGSERVER")

)
.route(buildRoute("/pdf-editor/discoveryserver/**","/pdf-editor/discoveryserver/(?<segment>.*)",
"/${segment}","discoveryServerCircuitBreaker"
,"/pdf-editor/fallback/contact-team","lb://DISCOVERYSERVER")

)

.build();
}
private Function<PredicateSpec, Buildable<Route>> buildRoute(String path, String rewritePath,String replacementPath, String circuitBreakerName, String fallbackUri,
String loadBalanceUri){
return predicateSpec -> predicateSpec.path(path).
filters(filterSpec->filterSpec.rewritePath(rewritePath,replacementPath)
.circuitBreaker(circuitConfi->
circuitConfi.setName(circuitBreakerName)
.setFallbackUri(fallbackUri)
.addStatusCode(HttpStatus.SERVICE_UNAVAILABLE.name())
))
.uri(loadBalanceUri);
}
@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> circuitBreakerFactoryCustomizer(){
return factory->factory.configureDefault(
Expand Down
Loading

0 comments on commit f9aac3d

Please sign in to comment.