繁体   English   中英

Spring 带外部配置服务调用的云网关过滤器

[英]Spring Cloud Gateway Filter with external configuration service call

我正在开发一个 Spring Cloud Gateway 应用程序,它有一个过滤器,可以根据不同服务持有的配置控制对某些路径或功能的访问。 因此,如果路径与功能 x 关联,则仅当配置服务返回功能 x 已启用时才允许访问。

配置以 Mono 的形式返回,然后进行平面映射以检查启用的功能。 这一切似乎都正常工作。 如果启用该功能,则允许请求通过链进行。 如果禁用该功能,则响应状态设置为禁止,请求标记为完成。 然而,这似乎并没有停止过滤器链,请求继续被处理并最终返回 200 响应。

如果功能配置不是从外部源返回并且立即可用,则此逻辑可以正常工作,但这涉及阻塞调用并且似乎不可取。 我看不出第一种方法有什么问题。 它似乎类似于其他地方可用的示例。

我相信我的问题与这个类似: https://stackoverflow.com/questions/73496938/spring-cloud-api-gateway-custom-filters-with-external-api-for-authorization/75095356#75095356

过滤器 1

这是我想这样做的方式:

override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        logger.info("Feature Security Filter")

        // getFeatures returns Mono<Map<String, Boolean>>
        return featureConfigService.getFeatures().flatMap { features ->
            val path = exchange.request.path.toString()
            val method = exchange.request.method.toString()

            if (featureMappings.keys.any { it.matcher(path).matches() }) {

                val pathIsRestricted = featureMappings
                        .filter { it.key.matcher(path).matches() }
                        .filter { features[it.value.requiresFeature] != true || !it.value.methodsAllowed.contains(method) }
                        .isNotEmpty()

                if (pathIsRestricted) {
                    logger.warn("Access to path [$method|$path] restricted. ")
                    exchange.response.statusCode = HttpStatus.FORBIDDEN
                    exchange.response.setComplete()
                    // processing should stop here but continues through other filters
                }
            }
            chain.filter(exchange);
        }
}

过滤器 2

这种方式可行,但涉及 featureService 中的阻塞调用。

override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        logger.info("Feature Security Filter")

        // this call returns a Map<String, Boolean> instead of a Mono
        val features = featureService.getFeatureConfig()
        val path = exchange.request.path.toString()
        val method = exchange.request.method.toString()
        if (featureMappings.keys.any { it.matcher(path).matches() }) {

            val pathIsRestricted = featureMappings
                    .filter { it.key.matcher(path).matches() }
                    .filter { features[it.value.requiresFeature] != true || !it.value.methodsAllowed.contains(method) }
                    .isNotEmpty()

            if (pathIsRestricted) {
                logger.warn("Access to path [$method|$path] restricted. ")

                val response: ServerHttpResponse = exchange.response
                response.statusCode = HttpStatus.FORBIDDEN;
                return response.setComplete()
                // this works as this request will complete here
            }
        }
        return chain.filter(exchange)
}

当测试运行时,我可以看到路径被正确记录为受限,并且响应状态按预期设置为 HttpStatus.FORBIDDEN,但请求继续由链中稍后的过滤器处理,并最终返回 200 响应。

我试过返回 Mono.error 和 onErrorComplete 的变体,但我得到了相同的行为。 我是 Spring 云网关的新手,看不出我做错了什么

在做了一些测试之后,我发现即使设置高阶,过滤器也会在路由过滤器之后执行。 如果你需要在路由之前过滤请求,你可以使用WebFilter 这是一个基于您的要求的工作 Java 示例。

package com.test.test.filters;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Map;

@Configuration
@Slf4j
public class TestGlobalFilter implements WebFilter, Ordered {

    private Mono<Map<String, Boolean>> test() {
        return Mono.just(Map.of("test", Boolean.TRUE));
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        log.info("Feature Security Filter");

        // getFeatures returns Mono<Map<String, Boolean>>
        return test().flatMap(features -> {

            final var isRestricted = features.get("test");

            if (Boolean.TRUE.equals(isRestricted)) {
                log.info("Feature Security stop");
                exchange.getResponse().setStatusCode(HttpStatus. FORBIDDEN);
                
                return exchange.getResponse().setComplete();
            }

            return chain.filter(exchange);
        });
    }
}


暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM