It is seems not advisable to register the name of your gateway filter in application.properties
. According to the respective Spring Developer Guide "this is not a supported naming convention" and should be avoided since it "may be removed in future releases". Here is the official advise:
Naming Custom Filters And References In Configuration
Custom filters class names should end in
GatewayFilterFactory
.
For example, to reference a filter namedSomething
in configuration files, the filter must be in a class namedSomethingGatewayFilterFactory
.
I am having troubles to make my gateway implementation work, too. In my case the Spring Cloud Starter Gateway (v.4.2.3) somehow expects an CSRF token. Whenever I hit the gateway with a POST request it anwers 403 Forbidden: An expected CSRF token cannot be found
I haven't figured out why this happens since I disabled Spring Security in all microservices downstreams. Here is what I got so far:
@Slf4j
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {
private final RouteValidator routeValidator;
private final JwtUtil jwtUtil;
public AuthGatewayFilterFactory(RouteValidator routeValidator, JwtUtil jwtUtil) {
super(Config.class);
this.routeValidator = routeValidator;
this.jwtUtil = jwtUtil;
}
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (routeValidator.isSecured.test(request)) {
String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (header == null || !header.trim().startsWith("Bearer ")) {
log.warn("Invalid authorization header");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
try {
jwtUtil.validateJwtToken(header);
} catch (JwtTokenMalformentException | JwtTokenMissingException e) {
log.error("Error during token validation: {}", e.getMessage());
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
String token = jwtUtil.getToken(header);
Claims claims = jwtUtil.extractAllClaims(token);
String csrfToken = request.getHeaders().getFirst("X-CSRF-TOKEN");
ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Username", claims.get("username", String.class))
.header("X-User-Email", claims.get("email", String.class))
.header("X-User-Roles", claims.get("roles", String.class))
.header("X-CSRF-TOKEN", csrfToken)
.build();
return chain.filter(exchange.mutate().request(mutatedRequest).build());
}
// Non-secured route — pass through unchanged
return chain.filter(exchange);
});
}
public static class Config {
private boolean validateCsrf = false;
public boolean isValidateCsrf() {
return validateCsrf;
}
public void setValidateCsrf(boolean validateCsrf) {
this.validateCsrf = validateCsrf;
}
}
}