본문 바로가기
정리/Spring Cloud

API gateway

by Hudini30 2022. 8. 7.

API Gateway 란?

클라이언트와 백엔드 서비스 컬렌션 사이에 위치하는 API 관리툴 입니다. 실제 백엔드 서비스 또는 데이터와 접속하고 API 호출에 대한  정책, 인증 및 일반 엑세스 제어를 적용하여 중요한 데이터를 보호하는 트랙픽 관리자

API Gateway 기능

1. 인증 및 권한 부여

2. 서비스 검색 통합

3. 응답 캐싱

4. 정책, 회로 차단기 및 QoS 다시 시도

5. 속도 제한

6. 부하 분산

7. 로깅, 추적, 상관 관계

8. 헤더, 쿼리 문자열 및 청구 변환

9. IP 허용 목록에 추가

 

Spring-cloud-gateway

RouteLocator Bean 생성으로 각 path에 대해 라우팅 할 수 있음

public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(route -> route.path("/user/**")
                        .filters(filter -> filter.addRequestHeader("user-request", "user-request-header")
                                .addResponseHeader("user-response", "user-response-header"))
                        .uri("http://localhost:8081/"))
                .route(route -> route.path("/order/**")
                        .filters(filter -> filter.addRequestHeader("order-request", "order-request-header")
                                .addResponseHeader("order-response", "order-response-header"))
                        .uri("http://localhost:8082/"))

                .build();
    }

 

YML 설정

spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      default-filters:
        - name: GlobalFilter
          args:
            baseMessage: Spring Cloud Gateway global Filter
            preLogger: true
            postLogger: true

      routes:
        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/order/**
          filters:
            - AddRequestHeader=order-request, order-requests-header2
            - AddResponseHeader=order-response, order-response-header2
            - name: LoggingFilter
              args:
                baseMessage: test
                preLogger: true
                postLogger: true
            - name: CustomFilter
            - RewritePath=/order/(?<segment>.*), /$\{segment}
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/user/**
            - Method=GET
          filters:
            - AddRequestHeader=user-request, user-requests-header2
            - AddResponseHeader=user-response, user-response-header2
            - CustomFilter
            - AuthorizationHeaderFilter
            - RewritePath=/user/(?<segment>.*), /$\{segment}
# Discovery Server에 등록
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

 

Custom Gateway Filter

AbstrctGatewayFilterFactory 를 상속 받아 구현

@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {

    private final Environment env;

    @Autowired
    public AuthorizationHeaderFilter(Environment env) {
        super(Config.class);
        this.env = env;
    }

    @Override
    public GatewayFilter apply(Config config) {
        GatewayFilter gatewayFilter = new OrderedGatewayFilter((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED);
            }

            String authorzationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
            String jwt = authorzationHeader.replace("Bearer", "");

            if (!isJwtValid(jwt)) {
                return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED);
            }

            return chain.filter(exchange);
        }, Ordered.HIGHEST_PRECEDENCE);

        return gatewayFilter;
    }

    private boolean isJwtValid(String jwt) {
        boolean returnValue = true;

        String subject = null;
        try {
            subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))
                    .parseClaimsJws(jwt)
                    .getBody()
                    .getSubject();
        } catch (Exception exception) {
            returnValue = false;
        }

        if (subject == null || subject.isEmpty()) {
            returnValue = false;
        }

        return returnValue;
    }

    private Mono<Void> onError(ServerWebExchange exchange, String message, HttpStatus httpStatus) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);
        return response.setComplete();
    }

    @Data
    public static class Config {
    }
}

 

'정리 > Spring Cloud' 카테고리의 다른 글

Spring Cloud Config  (0) 2022.08.07
Service Discovery  (0) 2022.06.28

댓글