ProgrammingBaKa
ProgrammingBaKa

Reputation: 373

Spring Cloud Gateway - Validate process within GatewayFilterChain

I am kind of new to the Spring reactor programming and currently I have encounter a requirement, which need to validate Authorization header within the spring GatewayFilterChain

which I have created a "AuthenticationFilter" with code snippet:

public class AuthenticationFilter implements GlobalFilter {
        @Autowired
        private WebClient.Builder webClientBuilder;

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            //Do API call to auth the "Authorization" Header data from the request
            AuthHeaderDto authHeaderDto = retrieveHeaderDto(exchange.getRequest());
            Mono<AuthResponse> monoAuthResponse = webClientBuilder.build().post()
                .uri(uri)
                .body(BodyInserters.fromPublisher(Mono.just(authHeaderDto), AuthHeaderDto.class))
                .retrieve()
                .bodyToMono(AuthResponse.class);

           //TODO: base on monoAuthResponse(parameter "isValid":true/false) 
           //      to set different status code (401 for false, 200 for true) to ServerWebExchange
           //      and continue the filter chain, i.e., return chain.filter(exchange);
        }
}

My Question is that the continue process of the chain actually need to wait for the validation request (i.e., blocking), in this context, in what way I can achieve that?

Thanks a lot for the help.

Upvotes: 0

Views: 1242

Answers (1)

nicholasnet
nicholasnet

Reputation: 2277

You can do something like this. Its not tested though.

@Component
public class GlobalGatewayPreFilter extends AbstractGatewayFilterFactory<GlobalGatewayPreFilter.Config> {

    private final WebClient client;

    @Autowired
    public GlobalGatewayPreFilter() {
        super(Config.class);
        this.client = WebClient.create("http://blahblah");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) ->
                exchange.getPrincipal()
                        .filterWhen(authenticationToken -> checkAuth(exchange))
                        .map(authenticationToken -> exchange)
                        .switchIfEmpty(Mono.defer(() -> setErrorResponse(exchange.getResponse()).setComplete().then(Mono.empty())))
                        .flatMap(chain::filter);
    }

    private ServerHttpResponse setErrorResponse(ServerHttpResponse serverHttpResponse) {

        serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);

        return serverHttpResponse;
    }

    private Mono<Boolean> checkAuth(ServerWebExchange exchange) {

        if (!exchange.getRequest().getHeaders().containsKey("Authorization")) {

            return Mono.empty();
        }

        // Map your response and send true false
        return Mono.just(true);
    }

    public static class Config {
        private String name;

        public String getName() {
            return this.name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

However I do not recommend doing this kind of Auth check in here. I would rather use Spring Security to do this but its up to you.

Upvotes: 1

Related Questions