I\'m adding some auth logic into cloud api gateway. I\'ve added GatewayFilter:
import java.util.List;
import org.sp
After some help from spring guys, I was able to make it work. So instead of writing directly to response I had to throw my custom exception and handle it properly:
@Bean
public ErrorWebExceptionHandler myExceptionHandler() {
return new MyWebExceptionHandler();
}
public class MyWebExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(
ServerWebExchange exchange, Throwable ex) {
byte[] bytes = "Some text".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
return exchange.getResponse().writeWith(Flux.just(buffer));
}
}
You should use ServerHttpResponseDecorator
to modify the response.
Your code should be like:
import java.util.List;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
public class AuthorizationFilter implements GatewayFilter {
@Override
public Mono<Void> filter(
ServerWebExchange exchange, GatewayFilterChain chain) {
List<String> authorization = exchange.getRequest().getHeaders().get("Authorization");
if (CollectionUtils.isEmpty(authorization) &&
!PatternMatchUtils.simpleMatch(URL_WITHOUT_AUTH, exchange.getRequest().getURI().toString())) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
return super.writeWith(fluxBody.map(dataBuffer -> {
// probably should reuse buffers
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
byte[] uppedContent = new String(content, Charset.forName("UTF-8")).toUpperCase().getBytes();
return bufferFactory.wrap(uppedContent);
}));
}
return super.writeWith(body); // if body is not a flux. never got there.
}
};
return chain.filter(exchange.mutate().response(decoratedResponse).build()); // replace response with decorator
}
String token = authorization.get(0).split(" ")[1];
// token validation
return chain.filter(exchange);
}
}
You can find a complete example here.