On Spring Cloud Gateway, we can apply some filters for each route. Whenever a request matches a route's path, the filters defined for that route will be executed. There are many things can be done using filters, such as modify request header, redirect to another URL, rewrite path and perform authentication. There are some built-in filters available to use. But, in case you need to implement custom filter, this tutorial shows you how to do so. I'm going to give you example of how to create custom filter by extending AbstractGatewayFilterFactory
.
To create a custom filter, we need to create a class that extends AbstractGatewayFilterFactory
. The AbstractGatewayFilterFactory
itself implements GatewayFilterFactory
. If you look at GatewayFilterFactory
, there is a method we need to implement GatewayFilter apply(C config)
. The other methods are already default, so there is only one method to be implemented.
Inside the apply
method is where we put the logic. Basically, we read the incoming request, process it with custom logic and modify the request before being passed to the route.
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
};
}
Inside the apply
, we should return a lambda function whose first argument is of type ServerWebExchange
and the second argument is of type GatewayFilterChain
. We can get the HTTP request (ServerHttpRequest
) using exchange.getRequest()
.
To return the modified request use chain.filter
whose argument is of type ServerWebExchange
as well.
In the example below, the filter is used to add another header if a header value is valid, but reject (return error 401) if the value is invalid or the header is not present.
package com.woolha.springcloudgateway.filter;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
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 MyFilter extends AbstractGatewayFilterFactory<MyFilter.Config> {
public MyFilter() {
super(Config.class);
}
private boolean isAuthorizationValid(String authorizationHeader) {
boolean isValid = true;
// Logic for checking the value
return isValid;
}
private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(httpStatus);
return response.setComplete();
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (!request.getHeaders().containsKey("Authorization")) {
return this.onError(exchange, "No Authorization header", HttpStatus.UNAUTHORIZED);
};
String authorizationHeader = request.getHeaders().get("Authorization").get(0);
if (!this.isAuthorizationValid(authorizationHeader)) {
return this.onError(exchange, "Invalid Authorization header", HttpStatus.UNAUTHORIZED);
}
ServerHttpRequest modifiedRequest = exchange.getRequest().mutate().
header("secret", RandomStringUtils.random(10)).
build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
};
}
public static class Config {
// Put the configuration properties
}
}
Then, use the filter on the route.
spring:
application:
name: springfield
cloud:
gateway:
routes:
- id: after_route
uri: lb://QUIMBY/authenticate
predicates:
- Method=POST
- Path=/authenticate
filters:
- MyFilter
Every time a request matches the predicate path, the filter will be executed first before the modified request passed to the URI.