Spring Cloud Gateway

박우영·2023년 6월 9일
0

Cloud

목록 보기
8/10

APIGateway


Setting

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 Handling

우리가 SCG 에서 원하는기능은 다음과 같습니다.

  1. 로드밸런싱
  2. CircuitBreaker
  3. 인증
  4. 네트워크 시각화의 편의성 향상

이중에서 로드밸런싱은 Eureka 를 활용하여 좀 더 간편하게 적용 할건데 밑에서 설정을 다루겠습니다.

중요한 기능중 하나인 인증 에 대해 다뤄볼겁니다.
우리서비스는 OIDC 프로토콜을 활용하여 SSO 로그인을 구현하고 이를 기반으로 JWT 를 별도로 생성 할겁니다.

cors

cors 는 application.yml 에 간단한 설정으로 해결할 수 있습니다.

      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: 'http://localhost:3000'
            allow-credentials: true
            allowedHeaders: "*"
            allowedMethods:
              - PUT
              - GET
              - POST
              - DELETE
              - OPTIONS

우선 Front-end 에서 테스트하기위해 localhost:3000 을 열어놨는데
중요한점은 yml 에 간단한 설정으로 해결할 수 있다는 점 입니다.

JWT 검증

앞서 말씀드렸던 것 처럼 우리는 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("토큰 검증 실패");
        }));
    }
}

제가 생각하는 이방식의 장점은 다음과 같습니다.

  • MicroService 에서 불필요한 네트워크를 처리할 필요가 없음
  • 공통된 로직을 Gateway 에서 한번에 구현함으로써 서비스들의 중복코드를 최소화 할 수 있음

Eureka


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

참고


Spring youtube
블로그

0개의 댓글