build.gradle
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
application.yml From APIGateway
management:
health:
redis:
enabled: false
spring:
cloud:
gateway:
routes:
- id: route1
uri: http://localhost:8080 ~ # 베이스 경로 입력
predicates:
- Path=/api/rule/v1/** # 경로 입력
#- Host=**.example.com
filters:
#- SetPath=/엔드포인트
Predicates: 라우트에 대한 요청이 해당 라우트의 조건에 맞는지를 확인하는 논리적인 조건입니다. 이것은 HTTP 요청의 여러 속성(예: 경로, 헤더, 쿼리 매개변수 등)에 대해 조건을 지정할 수 있습니다. 예를 들어, 경로 기반의 프리디케이트(Path=/user/**)는 /user로 시작하는 모든 URL의 요청이 해당 라우트에 매칭되도록 설정할 수 있습니다.
Filters: 필터는 라우트를 통해 요청이나 응답을 수정하는 데 사용됩니다. 예를 들어, 특정 헤더를 요청에 추가하거나, 경로를 재작성하는 등의 작업을 수행할 수 있습니다. 필터는 '전처리 필터(pre-filter)'와 '후처리 필터(post-filter)'로 분류될 수 있습니다. 전처리 필터는 프록시 요청이 실행되기 전에 수행되며, 후처리 필터는 프록시 요청이 실행된 후에 수행됩니다.
위처럼 설정한다면 게이트웨이 주소 + Path 값으로 api를 보낼 수 있습니다.
우리가 SCG 에서 원하는기능은 다음과 같습니다.
이중에서 로드밸런싱은 Eureka 를 활용하여 좀 더 간편하게 적용 할건데 밑에서 설정을 다루겠습니다.
중요한 기능중 하나인 인증 에 대해 다뤄볼겁니다.
우리서비스는 OIDC 프로토콜을 활용하여 SSO 로그인을 구현하고 이를 기반으로 JWT 를 별도로 생성 할겁니다.
cors 는 application.yml 에 간단한 설정으로 해결할 수 있습니다.
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: 'http://localhost:3000'
allow-credentials: true
allowedHeaders: "*"
allowedMethods:
- PUT
- GET
- POST
- DELETE
- OPTIONS
우선 Front-end 에서 테스트하기위해 localhost:3000 을 열어놨는데
중요한점은 yml 에 간단한 설정으로 해결할 수 있다는 점 입니다.
앞서 말씀드렸던 것 처럼 우리는 client 에서 오는 모든 요청을 Gateway로 통일 시켰습니다.
@Slf4j
@Component
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {
private StopWatch stopWatch;
@Autowired
private JwtUtil jwtUtil;
public static class Config{}
public GlobalFilter() {
super(GlobalFilter.Config.class);
stopWatch = new StopWatch("API Gatway");
}
@Override
public GatewayFilter apply(Config config) {
return (((exchange, chain) -> {
// Req , Res 객체 가져오기
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// Request 요청시 최초로 실행되는 필터
log.info("[Filter] REQUEST >>> IP : {}, URI : {}", request.getRemoteAddress(), request.getURI());
// 토큰 검증
try {
String jwtToken = request.getHeaders().getFirst("Authorization");
if (jwtUtil.validateToken(jwtToken)) {
return chain.filter(exchange);
}
} catch (NullPointerException e) {
throw new TokenValidException("토큰이 없습니다.");
}
throw new TokenValidException("토큰 검증 실패");
}));
}
}
제가 생각하는 이방식의 장점은 다음과 같습니다.
Eureka 는 Neflix에서 제공한 MSA를 위한 클라우드 오픈 소스입니다.
장점으로는 REST API 로 송수신 하기때문에 java,Spring 뿐만아니라 그 외의 python django 와 같은 다른 언어, 프레임워크랑도 연동 할 수 있습니다.
또한 기존의 routes 의 uri 도 간편하게 작성가능합니다.
application.yml From APIGateway (Eureka)
spring:
cloud:
gateway:
routes:
- id: rule-service
uri: lb://rule-service
predicates:
- Path=/api/rule/v1/**
build.gradle From APIGateway
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
application.yml From Eureka-Server
# eureka default port = 8761
server:
port: 8761
# identify name in MSA
spring:
application:
name: eureka-server
# make client setting false
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
application.yml From application
spring:
mvc:
pathmatch:
matching-strategy: path_pattern_parser
application:
name: rule-service
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://127.0.0.1:8761/eureka/
eureka 의 설정은 eureka 서버에 등록하는지 묻는것입니다. 등록할 거기때문에 true
defaultZone 은 유레카 서버 주소
postman -> APIGateway -> Eureka-Server-> Rule-Service