0

我正在使用 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 中的过滤器来实现这一点。

4

1 回答 1

0

是的,这是一个阻塞调用。

首先,Spring WebFlux 基于 Reactor。在 Reactor 中,大多数处理方法都不会收到null来自Monoemit 的 a,map例如flatMap. 当然,也有反例,例如doOnSuccess,另请参阅 的javadocMono

因此,我们可以只使用处理方法来过滤结果,而不是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

于 2020-07-13T03:08:11.740 回答