27 Temmuz 2021 Salı

SpringCloud Gateway GatewayFilter Arayüzü - Belirli Bir Route İçin Kullanılır

Giriş
Şu satırı dahil ederiz
import org.springframework.cloud.gateway.filter.GatewayFilter;
GlobalFilter ve GatewayFilter benziyorlar. Açıklaması şöyle
Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in GatewayFilter Factories.
Örnek
Şöyle yaparız
//Apply filter for a specific route using spring inbuilt filter //"AddRequestHeader"
spring.cloud.gateway.routes[0].filters[0]=AddRequestHeader=first-request-header, 
  first-request-header-value
Örnek
Elimizde şöyle bir kod olsun
@RefreshScope
@Component
public class AuthenticationFilter implements GatewayFilter {

  @Autowired
  private RouterValidator routerValidator;//custom route validator
  @Autowired
  private JwtUtil jwtUtil;

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request = exchange.getRequest();

    if (routerValidator.isSecured.test(request)) {
      if (this.isAuthMissing(request))
        return this.onError(exchange, "Authorization header is missing in request",
HttpStatus.UNAUTHORIZED);

      final String token = this.getAuthHeader(request);

      if (jwtUtil.isInvalid(token))
        return this.onError(exchange, "Authorization header is invalid",
HttpStatus.UNAUTHORIZED);

      this.populateRequestWithHeaders(exchange, token);
    }
        return chain.filter(exchange);
    }

  ...
}
Yardımcı metodlar için şöyle yaparız
private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
  ServerHttpResponse response = exchange.getResponse();
  response.setStatusCode(httpStatus);
  return response.setComplete();
}

private String getAuthHeader(ServerHttpRequest request) {
  return request.getHeaders().getOrEmpty("Authorization").get(0);
}

private boolean isAuthMissing(ServerHttpRequest request) {
  return !request.getHeaders().containsKey("Authorization");
}

private void populateRequestWithHeaders(ServerWebExchange exchange, String token) {
  Claims claims = jwtUtil.getAllClaimsFromToken(token);
  exchange.getRequest().mutate()
    .header("id", String.valueOf(claims.get("id")))
    .header("role", String.valueOf(claims.get("role")))
    .build();
}
RouterValidator kodu şöyledir
@Component
public class RouterValidator {

  public static final List<String> openApiEndpoints = List.of(
    "/auth/register",
    "/auth/login"
  );

  public Predicate<ServerHttpRequest> isSecured =
    request -> openApiEndpoints
      .stream()
      .noneMatch(uri -> request.getURI().getPath().contains(uri));
}
Filtreyi kullanmak için şöyle yaparız
@Configuration
@EnableHystrix
public class GatewayConfig {

  @Autowired
  AuthenticationFilter filter;

  @Bean
  public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
      .route("user-service", r -> r.path("/users/**")
        .filters(f -> f.filter(filter))
        .uri("lb://user-service"))

      .route("auth-service", r -> r.path("/auth/**")
        .filters(f -> f.filter(filter))
        .uri("lb://auth-service"))
      .build();
    }
}
Açıklaması şöyle 
- all requests that starts with /users/** should be routed to user service, and our custom JWT filter should be applied to each such request 
- all requests that starts with /auth/** should be routed to auth service, and our custom JWT filter should be applied to each such request too.
Örnek
Şöyle yaparız
public class CustomerRateLimitFilter extends
AbstractGatewayFilterFactory<CustomerRateLimitFilter.Config> {
  private final RateLimiter<?> rateLimiter = ...;
  private final KeyResolver keyResolver = ...;
       
  @Override
  public GatewayFilter apply(Config config) {
    return new OrderedGatewayFilter((exchange, chain) -> {

      Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
      return keyResolver.resolve(exchange).flatMap(key -> {
        if (StringUtil.isNullOrEmpty(key)) {
          return handleErrorResponse(exchange, HttpStatus.UNPROCESSABLE_ENTITY);
        }
        Mono<RateLimiter.Response> result = rateLimiter.isAllowed(route.getId(), key);
        return result.flatMap(response -> {

        response.getHeaders().forEach((k, v) -> exchange.getResponse().getHeaders()
.add(k, v));

          if (response.isAllowed()) {
            return chain.filter(exchange);
          }
          return handleErrorResponse(exchange, HttpStatus.TOO_MANY_REQUESTS);
        });
      });
    }, RATELIMIT_ORDER);
  }
 
}
Kullanmak için şöyle yaparız
spring:
  cloud:
    gateway:
      routes:
        - id: face-match-api-route
          uri: http://localhost:8800
          predicates:
            - Path=/face/**
          filters:
            - StripPrefix=1
            - name: CustomerRateLimitFilter
            - name: CustomerQuotaFilter

Hiç yorum yok:

Yorum Gönder