코드 분석 - Spring Gateway

장숭혁·2024년 8월 14일
0

TIL작성

목록 보기
52/60

Spring Gateway 부분

Config

// FeignClient 를 Lazy Load 할 경우 HttpMessageConverters 문제로 아래 config 설정이 필요합니다.
// open issue https://github.com/spring-cloud/spring-cloud-openfeign/issues/235
@Configuration
public class FeignConfig {
    @Bean
    public Decoder feignDecoder() {

        ObjectFactory<HttpMessageConverters> messageConverters = () -> {
            HttpMessageConverters converters = new HttpMessageConverters();
            return converters;
        };
        return new SpringDecoder(messageConverters);
    }
}

FeignClient를 지연 로딩(Lazy Load)할 때 발생할 수 있는 HttpMessageConverters 관련 문제를 해결하기 위한 설정이다. FeignClient를 사용하여 다른 서비스와의 통신을 진행할때 HttpMessageConverters는 직렬화 역직렬화를 담당한다.

  • FeignClient를 지연로딩 한다면 실제로 그 메소드를 쓰기 전까지 빈에 등록되지 않는다.
    -> 메모리 사용량을 아낀다, 애플리케이션 시작시간 단축

  • HttpMessageConverters : spring에서 http 요청/응답을 객체로 변환할 때 사용한다.

  • ObjectFactory messageConverters: HttpMessageConverters - FeignClient가 필요할 때 HttpMessageConverters를 적절하게 사용할 수 있게함

  • feignDecoder 메서드에서 이 디코더를 빈으로 등록함으로써, Feign이 이를 사용하여 HTTP 응답을 처리할 수 있게 된다.

    yml 파일

  server:
  port: 19091

spring:
  main:
    web-application-type: reactive
  application:
    name: gateway-service
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order/** # /order 로 시작하는 모든 요청은 eureka application name: order-service 로 호출되도록 설정합니다.
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/products/** # /products 로 시작하는 모든 요청은 eureka application name: product-service 로 호출되도록 설정합니다.
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/auth/** # /auth 로 시작하는 모든 요청은 eureka application name: auth-service 로 호출되도록 설정합니다.
      discovery:
        locator:
          enabled: true

service:
  jwt:
    secret-key: "401b09eab3c013"

eureka:
  client:
    service-url:
      defaultZone: http://localhost:19090/eureka/
  • web-application-type: reactive : 리액티브 웹 애플리케이션으로 동작하도록 설정한다. Spring WebFlux를 기반, 비동기이다.

  • name: gateway-service : eureka에 등록할 때 사용함

    spring:
    cloud:
      gateway:
        routes:
          - id: order-service
            uri: lb://order-service
            predicates:
              - Path=/order/**
          - id: product-service
            uri: lb://product-service
            predicates:
              - Path=/products/**
          - id: auth-service
            uri: lb://auth-service
            predicates:
              - Path=/auth/**
        discovery:
          locator:
            enabled: true
  • id: 각 라우트의 식별자

  • uri: 라우팅할 목적지 URI, lb://는 로드 밸런싱을 의미, Eureka에서 해당 서비스의 인스턴스를 동적으로 발견하고 로드 밸런싱하는 데 사용

  • predicates: 요청을 특정 조건에 따라 라우팅한다 여기서는 요청 경로(Path)가 특정 패턴(/order/, /products/, /auth/**)에 일치하는 경우 해당 마이크로서비스로 요청을 전달한다.

  • Discovery Locator: enabled: true로 설정하면 Gateway는 Eureka에 등록된 모든 서비스를 자동으로 탐지하고, 그에 따라 라우트를 동적으로 구성한다.

    @Component
    public class LocalJwtAuthenticationFilter implements GlobalFilter {
    
      private final String secretKey;
    
      private final AuthService authService;
    
      // FeignClient 와 Global Filter 의 순환참조 문제가 발생하여 Bean 초기 로딩 시 순환을 막기 위해 @Lazy 어노테이션을 추가함.
      public LocalJwtAuthenticationFilter(@Value("${service.jwt.secret-key}") String secretKey, @Lazy AuthService authService) {
          this.secretKey = secretKey;
          this.authService = authService;
      }
    
      // 필수 과제 - 외부 요청 보호 GlobalFilter
      @Override
      public Mono<Void> filter(final ServerWebExchange exchange, final GatewayFilterChain chain) {
          // 접근하는 URI 의 Path 값을 받아옵니다.
          String path = exchange.getRequest().getURI().getPath();
          // /auth 로 시작하는 요청들은 검증하지 않습니다.
          if (path.startsWith("/auth")) {
              return chain.filter(exchange);
          }
    
          String token = extractToken(exchange);
          // 토큰이 존재하지 않거나, validateToken(token) 기준에 부합하지 않으면 401 에러를 응답합니다.
          if (token == null || !validateToken(token)) {
              exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
              return exchange.getResponse().setComplete();
          }
    
          return chain.filter(exchange);
      }
    .... 이하부터는 토큰 관련 메소드
  • LocalJwtAuthenticationFilter : 모든 요청을 가로채서 JWT 토큰을 검증하고, 유효하지 않은 요청에 대해서는 401(Unauthorized) 상태 코드를 반환, GlobalFilter 인터페이스를 구현하여 Spring Cloud Gateway에서 모든 요청에 대해 전역적으로 작동하는 필터를 정의

  • @Lazy AuthService authService : 순환 참조 문제를 해결하기 위해서 사용됨, 빈의 초기 로딩 시점에 발생할 수 있는 순환 참조 문제를 방지

  • ServerWebExchange : 현재 HTTP 요청/응답과 관련된 정보에 접근할 수 있는 객체

  • GatewayFilterChain: 현재 필터 체인의 다음 필터를 호출하기 위한 객체

  • filter 메소드 동작 순서

    • uri 를 추출해 auth 로 시작하는 요청이면 다음 필터로 통과시킴
    • 토큰이 존재하지 않거나 유효하지 않으면 401 에러를 발생시킴
    • 토큰이 유효하면 다음 필터 진행
public interface AuthService {
    Boolean verifyUser(String userId);
}
  
  @FeignClient(name = "auth-service")
public interface AuthClient extends AuthService {
    @GetMapping("/auth/verify") // 유저 검증 API
    Boolean verifyUser(@RequestParam(value = "user_id") String userId);
}
  • AuthClient는 AuthService를 상속받아 사용한다.
  • name = "auth-service" : Eureka에 등록된 서비스를 호출할 것임
  • AuthService 인터페이스를 상속받음으로써 재사용성을 높이고 결합도를 낮춘 설계
profile
코딩 기록

0개의 댓글

관련 채용 정보