## RemoteAddrRoutePredicateFactory类
public Predicate apply(RemoteAddrRoutePredicateFactory.Config config) {//获取yml配置的地址信息,如下图获取的到地址是192.168.21.21final List sources = this.convert(config.sources);return new GatewayPredicate() {public boolean test(ServerWebExchange exchange) {//获取请求的地址(执行的代码就是下面那一个方法) 如下图获取到的是192.168.21.100InetSocketAddress remoteAddress = config.remoteAddressResolver.resolve(exchange);if (remoteAddress != null && remoteAddress.getAddress() != null) {String hostAddress = remoteAddress.getAddress().getHostAddress();String host = exchange.getRequest().getURI().getHost();if (RemoteAddrRoutePredicateFactory.log.isDebugEnabled() && !hostAddress.equals(host)) {RemoteAddrRoutePredicateFactory.log.debug("Remote addresses didn't match " + hostAddress + " != " + host);}Iterator var5 = sources.iterator();while(var5.hasNext()) {IpSubnetFilterRule source = (IpSubnetFilterRule)var5.next();//通过正则匹配判断是否通过if (source.matches(remoteAddress)) {return true;}}}return false;}public Object getConfig() {return config;}public String toString() {return String.format("RemoteAddrs: %s", config.getSources());}};
}## RemoteAddressResolver类
default InetSocketAddress resolve(ServerWebExchange exchange) {//获取直接连接网关的IP地址,如果通nginx转发到网关的,那么这里获取到的是nginx的IP地址。return exchange.getRequest().getRemoteAddress();
}
yml配置:
如果我们在yml的断言配置如下图,那么他将匹配不成功
## XForwardedRemoteAddrRoutePredicateFactory类
public Predicate apply(XForwardedRemoteAddrRoutePredicateFactory.Config config) {if (log.isDebugEnabled()) {log.debug("Applying XForwardedRemoteAddr route predicate with maxTrustedIndex of " + config.getMaxTrustedIndex() + " for " + config.getSources().size() + " source(s)");}org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory.Config wrappedConfig = new org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory.Config();/*** 获取yml配置的IP地址信息,将从获取yml配置的IP地址信息传递* 给RemoteAddrRoutePredicateFactory,如下图获取的到地址是192.168.21.21*/wrappedConfig.setSources(config.getSources());/*** config.getMaxTrustedIndex() 默认值为 1* XForwardedRemoteAddressResolver重新了resolve这个方法,用来获取请求头中X-Forwarded-For的值*/wrappedConfig.setRemoteAddressResolver(XForwardedRemoteAddressResolver.maxTrustedIndex(config.getMaxTrustedIndex()));//说明RemoteAddrRoutePredicateFactory底层还是用RemoteAddr断言的规则RemoteAddrRoutePredicateFactory remoteAddrRoutePredicateFactory = new RemoteAddrRoutePredicateFactory();//将封装好的config传递给RemoteAddrRoutePredicateFactoryPredicate wrappedPredicate = remoteAddrRoutePredicateFactory.apply(wrappedConfig);return (exchange) -> {Boolean isAllowed = wrappedPredicate.test(exchange);if (log.isDebugEnabled()) {ServerHttpRequest request = exchange.getRequest();log.debug("Request for \"" + request.getURI() + "\" from client \"" + request.getRemoteAddress().getAddress().getHostAddress() + "\" with \"" + "X-Forwarded-For" + "\" header value of \"" + request.getHeaders().get("X-Forwarded-For") + "\" is " + (isAllowed ? "ALLOWED" : "NOT ALLOWED"));}return isAllowed;};
}## RemoteAddrRoutePredicateFactory类
public Predicate apply(RemoteAddrRoutePredicateFactory.Config config) {//获取传递过来的IP地址,如下图获取的到地址是192.168.21.21final List sources = this.convert(config.sources);return new GatewayPredicate() {public boolean test(ServerWebExchange exchange) {//获取请求的地址(执行的代码就是下面那一个方法) 如下图获取到的是192.168.21.22InetSocketAddress remoteAddress = config.remoteAddressResolver.resolve(exchange);if (remoteAddress != null && remoteAddress.getAddress() != null) {String hostAddress = remoteAddress.getAddress().getHostAddress();String host = exchange.getRequest().getURI().getHost();if (RemoteAddrRoutePredicateFactory.log.isDebugEnabled() && !hostAddress.equals(host)) {RemoteAddrRoutePredicateFactory.log.debug("Remote addresses didn't match " + hostAddress + " != " + host);}Iterator var5 = sources.iterator();while(var5.hasNext()) {IpSubnetFilterRule source = (IpSubnetFilterRule)var5.next();//通过正则匹配判断是否通过if (source.matches(remoteAddress)) {return true;}}}return false;}...};
}## XForwardedRemoteAddressResolver类
public InetSocketAddress resolve(ServerWebExchange exchange) {//获取请求头中X-Forwarded-For的值List xForwardedValues = this.extractXForwardedValues(exchange);Collections.reverse(xForwardedValues);if (!xForwardedValues.isEmpty()) {//获取指定位置的IP,int index = Math.min(xForwardedValues.size(), this.maxTrustedIndex) - 1;return new InetSocketAddress((String)xForwardedValues.get(index), 0);} else {return this.defaultRemoteIpResolver.resolve(exchange);}
}## XForwardedRemoteAddressResolver类
private List extractXForwardedValues(ServerWebExchange exchange) {List xForwardedValues = exchange.getRequest().getHeaders().get("X-Forwarded-For");if (xForwardedValues != null && !xForwardedValues.isEmpty()) {//如果X-Forwarded-For的值多个直接丢弃if (xForwardedValues.size() > 1) {log.warn("Multiple X-Forwarded-For headers found, discarding all");return Collections.emptyList();} else {List values = Arrays.asList(((String)xForwardedValues.get(0)).split(", "));return values.size() == 1 && !StringUtils.hasText((String)values.get(0)) ? Collections.emptyList() : values;}} else {return Collections.emptyList();}
}
因config.getMaxTrustedIndex()
的默认值为1,所以请求头X-Forwarded-For
值的最后一个值,如下图,获取的值为192.168.21.22。
如果我们在yml的断言配置如下图,那么他将匹配不成功。
XForwardedRemoteAddressResolver有两个静态构造函数方法,它们采用不同的安全方法:
XForwardedRemoteAddressResolver::trustAllRemoteAddressResolver返回始终采用标头中找到的第一个 IP 地址的a X-Forwarded-For。这种方法容易受到欺骗,因为恶意客户端可以为 设置一个初始值X-Forwarded-For,解析器会接受该值。
XForwardedRemoteAddressResolver::maxTrustedIndex采用与在 Spring Cloud Gateway 前面运行的可信基础设施数量相关的索引。例如,如果 Spring Cloud Gateway 只能通过 HAProxy 访问,则应使用值 1。如果在访问 Spring Cloud Gateway 之前需要两跳可信基础设施,则应使用值 2。
上一篇:麦肯锡极简发展简史