Проверить доступ к базе данных в предварительном фильтре Spring Gateway - PullRequest
0 голосов
/ 12 июля 2020

Я использую Spring Gateway, где мне нужно проверить дальнейший доступ пользователей по пути запроса с использованием вызова DB. Мой репозиторий выглядит следующим образом.

public Mono<ActionMapping> getByUri(String url)
....

Это мой текущий фильтр, в котором я использую индивидуальную реализацию UsernamePasswordAuthenticationToken.

@Override
public GatewayFilter apply(Config config) {

    return (exchange, chain) -> exchange
        .getPrincipal()
        .filter(principal -> principal instanceof UserAuthenticationToken) // Custom implementation of UsernamePasswordAuthenticationToken
        .cast(UserAuthenticationToken.class)
        .map(userAuthenticationToken -> extractAuthoritiesAndSetThatToRequest(exchange, userAuthenticationToken))
        .defaultIfEmpty(exchange)
        .flatMap(chain::filter);
}

private ServerWebExchange extractAuthoritiesAndSetThatToRequest(ServerWebExchange exchange, UserAuthenticationToken authentication) {

    var uriActionMapping = uriActionMappingRepository.findOneByUri(exchange.getRequest().getPath().toString()).block();

    if ((uriActionMapping == null) || (authentication.getPermission().containsKey(uriActionMapping.getName()))) {

        ServerHttpRequest request = exchange.getRequest()
                                            .mutate()
                                            .header("X-Auth", authentication.getName())
                                            .build();

        return exchange.mutate().request(request).build();
    }

    ServerHttpResponse response = exchange.getResponse();
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
    response.setComplete();

    return exchange.mutate().response(response).build();
}

Однако здесь есть несколько проблем, во-первых, это блокирует звонок. Также я не уверен, что мне нужно изменить exchange, чтобы вернуть такой ответ. Есть ли способ добиться этого с помощью фильтра в Spring Cloud Gateway.

1 Ответ

0 голосов
/ 13 июля 2020

Да, это вызов блокировки.

Во-первых, Spring WebFlux основан на Reactor. В Reactor большинство методов обработки не будут получать null от Mono emit, например map, flatMap. Конечно, есть контрпримеры, такие как doOnSuccess, см. Также javado c из Mono.

Итак, мы можем просто использовать методы обработки для фильтрации результатов вместо block. Эти методы обработки возвращают пустой Mono при получении значения null.

Вторичный, когда авторизация не удалась, мы должны вернуть пустой Mono вместо вызова chain.filter. chain.filter означает «Все нормально! Просто сделайте что-нибудь после фильтра!». См. Также RequestRateLimiterGatewayFilterFactory, он также изменяет response.

Итак, мы должны установить response как завершенное и вернуть пустой Mono, если авторизация не удалась.

Попробуйте это :

@Override
public GatewayFilter apply(Config config) {
    return (exchange, chain) -> exchange
        .getPrincipal()
        .filter(principal -> principal instanceof UserAuthenticationToken) // Custom implementation of UsernamePasswordAuthenticationToken
        .cast(UserAuthenticationToken.class)
        .flatMap(userAuthenticationToken -> extractAuthoritiesAndSetThatToRequest(exchange, userAuthenticationToken))
        .switchIfEmpty(Mono.defer(() -> exchange.getResponse().setComplete().then(Mono.empty())))
        .flatMap(chain::filter);
}

// Maybe return empty Mono, e.g. findOneByUri not found, or Permissions does not containing
private Mono<ServerWebExchange> extractAuthoritiesAndSetThatToRequest(ServerWebExchange exchange, UserAuthenticationToken authentication) {
    return uriActionMappingRepository.findOneByUri(exchange.getRequest().getPath().toString())
        .filter(it -> authentication.getPermission().containsKey(it.getName()))
        .map(it -> exchange.mutate()
            .request(builder -> builder.header("X-Auth", authentication.getName()))
            .build());
}

О mutate request, см. Также RewritePathGatewayFilterFactory.

...