Spring Cloud Gateway
Spring Cloud Gateway는 MSA에서 클라이언트 요청의 단일 진입점 역할을 수행
클라이언트의 요청을 받아 라우팅 규칙에 따라 적절한 서비스로 요청을 전달하고 응답을 다시 클라이언트에게 전달하는 역할을 함
WebFlux
비동기 및 논블로킹 방식으로 동작하는 웹 프레임워크
소수의 스레드가 많은 요청을 효율적으로 처리. 요청 처리 중 작업에서 대기하는 동안 스레드를 해제하고 다른 요청 청리
Gradle
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
}
ext {
set('springCloudVersion', "2023.0.0")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
application.yml
server:
port: 8000
spring:
application:
name: api-gateway-service
cloud:
gateway:
routes:
- id: auth-service-route
uri: http://localhost:8080
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
- AuthorizationHeaderFilter
jwt:
secret:~
(라우팅 설정)
게이트웨이의 핵심 '이정표'
- predicates: /auth/**로 들어오는 요청을 감지
- filters: 요청이 전달되기 전 StripPrefix=1(경로 제거)과 커스텀 필터인 AuthorizationHeaderFilter를 순차적으로 실행
AuthorizationHeaderFilter.java
package com.example.distributed.filter;
import com.example.distributed.util.JwtTokenProvider;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
@Component
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {
private final JwtTokenProvider jwtTokenProvider;
public AuthorizationHeaderFilter(JwtTokenProvider jwtTokenProvider) {
super(Config.class);
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
return onError(exchange, "Authorization header missing", HttpStatus.UNAUTHORIZED);
}
List<String> authorizationHeaders = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
if (authorizationHeaders == null || authorizationHeaders.isEmpty()) {
return onError(exchange, "Authorization header missing", HttpStatus.UNAUTHORIZED);
}
String authorizationHeader = authorizationHeaders.get(0);
String jwt = authorizationHeader.replace("Bearer ", "");
if (!jwtTokenProvider.validateToken(jwt)) {
return onError(exchange, "JWT token is not valid or expired", HttpStatus.UNAUTHORIZED);
}
String userId = jwtTokenProvider.getUsername(jwt);
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
};
}
private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(httpStatus);
System.err.println("API Gateway JWT Error: " + err);
return response.setComplete();
}
public static class Config {
}
}
(통합 인증 필터)
각 서비스마다 중복으로 존재하던 인증 로직을 게이트웨이로 모음
- 토큰 검증: JwtTokenProvider를 사용해 모든 요청의 JWT 유효성을 입구에서 컷트
- 헤더 변조 (Request Mutation): 토큰에서 꺼낸 userId를 X-User-Id라는 새로운 헤더에 담아 내부 서비스로 전달. 이를 통해 내부 서비스들은 복잡한 JWT 해석 없이 헤더값만 읽어서 사용자를 식별
- 비동기 에러 처리: Mono<Void>를 반환하여 WebFlux 방식에 맞는 논블로킹 응답 처리를 수행
중앙 집중식 인증 및 보안 관리
- 이점: 모든 마이크로서비스가 각자 인증 로직을 가질 필요가 없음
- 실제 효과: 인증 로직에 수정이 필요할 때 게이트웨이의 필터 하나만 고치면 모든 서비스에 즉시 적용됩니다. 보안 취약점 노출 범위를 최소화
내부 서비스의 단순화 (Service Abstraction)
- 이점: 내부 서비스(Auth, User 등)는 더 이상 JWT나 보안 설정을 신경 쓰지 않아도 됨.
- 실제 효과: 내부 서비스는 단순히 게이트웨이가 넘겨준 X-User-Id 헤더만 믿고 비즈니스 로직에만 집중하면 됩니다. 서비스 간 결합도가 획기적으로 낮아짐
고성능 비동기 처리 (WebFlux)
- 이점: 동기(Blocking) 방식보다 훨씬 많은 연결을 동시에 수용 가능
- 실제 효과: API Gateway는 모든 트래픽이 몰리는 병목 지점이 되기 쉬운데, WebFlux의 논블로킹 특성 덕분에 대규모 트래픽 상황에서도 시스템이 뻗지 않고 안정적으로 요청을 배분
클라이언트와의 통신 단일화
- 이점: 클라이언트는 내부 서비스들의 주소(IP, 포트)를 알 필요가 없음
- 실제 효과: 포트 8000번(Gateway) 하나만 알면 모든 기능을 이용할 수 있으며, 내부 서버의 위치가 바뀌거나 서비스가 증설되어도 클라이언트 코드를 수정할 필요가 없음
feat: Spring Cloud Gateway 도입 및 JWT 인증/인가 필터 구현 by 0hj1hyeon · Pull Request #5 · 0hj1hyeon/distributed
AuthorizationHeaderFilter를 구현
github.com
'분산 처리 환경' 카테고리의 다른 글
| 스프링 분산 처리 환경 8: Spring Cloud Gateway, JWT 인가 필터 및 경로별 라우팅 검증 테스트 (1) | 2025.11.19 |
|---|---|
| 스프링 분산 처리 환경 7: Spring Cloud Gateway 환경에서 JWT 인증 (1) | 2025.11.17 |
| 스프링 분산 처리 환경 5: DB 연동 (0) | 2025.11.13 |
| 스프링 분산 처리 환경 4: BCryptPasswordEncoder (1) | 2025.11.12 |
| 스프링 분산 처리 환경 3: Spring Security (0) | 2025.11.11 |