From e8cf276fce4ffe6787857f821ae395abf4bfd729 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Mon, 20 Feb 2023 18:18:15 +0800 Subject: [PATCH 1/8] Support request path end with or without / --- .../fizzgate/plugin/auth/ServiceConfig.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java b/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java index 292522e..1396879 100644 --- a/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java +++ b/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java @@ -18,6 +18,7 @@ package com.fizzgate.plugin.auth; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fizzgate.util.Consts; import com.fizzgate.util.ThreadContext; import com.fizzgate.util.UrlTransformUtils; @@ -124,18 +125,22 @@ public class ServiceConfig { } private void checkPathPattern(Map> pathPattern2apiConfigMap, boolean dedicatedLineRequest, String path, ArrayList result) { + String path0 = path; + if (!path.equals(Consts.S.FORWARD_SLASH_STR)) { + int lastCharPos = path.length() - 1; + char c = path.charAt(lastCharPos); + if (c == Consts.S.FORWARD_SLASH) { + path0 = path.substring(0, lastCharPos); + } else { + path0 = path + Consts.S.FORWARD_SLASH; + } + } Set>> entries = pathPattern2apiConfigMap.entrySet(); - // boolean clear = false; for (Map.Entry> entry : entries) { String pathPattern = entry.getKey(); Set apiConfigs = entry.getValue(); - if (pathPattern.equals(path)) { + if (pathPattern.equals(path) || pathPattern.equals(path0)) { for (ApiConfig ac : apiConfigs) { -// if (ac.allowAccess) { - /*if (!clear && !result.isEmpty()) { - result.clear(); - clear = true; - }*/ if (dedicatedLineRequest) { if (ac.dedicatedLine) { result.add(ac); @@ -145,14 +150,9 @@ public class ServiceConfig { result.add(ac); } } -// } } - /*if (clear && !result.isEmpty()) { - return; - }*/ - } else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) { + } else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path) || UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path0)) { for (ApiConfig ac : apiConfigs) { -// if (ac.allowAccess) { if (dedicatedLineRequest) { if (ac.dedicatedLine) { result.add(ac); @@ -162,9 +162,8 @@ public class ServiceConfig { result.add(ac); } } -// } } } - } // end for + } } } From 6052760f4ca8eebd2639f338c1fa911b56951e6f Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Thu, 16 Mar 2023 11:59:25 +0800 Subject: [PATCH 2/8] Support HMAC algorithm functions #470 --- .../com/fizzgate/fizz/function/CodecFunc.java | 34 ++++++++++++++++++- .../fizz/function/CodecFuncTests.java | 7 ++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java index 23ad4b1..8044e04 100644 --- a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java +++ b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java @@ -27,6 +27,8 @@ import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.digest.HmacAlgorithms; +import org.apache.commons.codec.digest.HmacUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,7 +48,7 @@ public class CodecFunc implements IFunc { private static final String CHARSET_UTF8 = "UTF-8"; private static final String IV = "12345678"; - + private static CodecFunc singleton; public static CodecFunc getInstance() { @@ -77,6 +79,12 @@ public class CodecFunc implements IFunc { FuncExecutor.register(NAME_SPACE_PREFIX + "codec.aesDecrypt", this); FuncExecutor.register(NAME_SPACE_PREFIX + "codec.desEncrypt", this); FuncExecutor.register(NAME_SPACE_PREFIX + "codec.desDecrypt", this); + FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacMd5", this); + FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha1", this); + FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha224", this); + FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha256", this); + FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha384", this); + FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha512", this); } public String md5(String data) { @@ -180,5 +188,29 @@ public class CodecFunc implements IFunc { throw e; } } + + public String hmacMd5(String secretKey, String data) { + return new HmacUtils(HmacAlgorithms.HMAC_MD5, secretKey).hmacHex(data); + } + + public String hmacSha1(String secretKey, String data) { + return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, secretKey).hmacHex(data); + } + + public String hmacSha224(String secretKey, String data) { + return new HmacUtils(HmacAlgorithms.HMAC_SHA_224, secretKey).hmacHex(data); + } + + public String hmacSha256(String secretKey, String data) { + return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(data); + } + + public String hmacSha384(String secretKey, String data) { + return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, secretKey).hmacHex(data); + } + + public String hmacSha512(String secretKey, String data) { + return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, secretKey).hmacHex(data); + } } diff --git a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java index 750abc9..4c79872 100644 --- a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java +++ b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java @@ -122,5 +122,12 @@ class CodecFuncTests { Object result = FuncExecutor.getInstance().exec(null, funcExpression); assertEquals("abc", result.toString()); } + + @Test + void testHmacSha256() { + String funcExpression = "fn.codec.hmacSha256(\"635e8562b968bc05bb80cacf124ebd53285280ee6845df0000faa33acafc38f0\", \"12345678123456781234567812345678\")"; + Object result = FuncExecutor.getInstance().exec(null, funcExpression); + assertEquals("c61be0237ec186df1c5f51425e607093b260a76e5de43a62cb3e821103303990", result.toString()); + } } \ No newline at end of file From 49134c52d6df61110bdcda6589aa4dd4aa947fcf Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Thu, 16 Mar 2023 14:31:47 +0800 Subject: [PATCH 3/8] Support HMAC algorithm functions #470 --- .../java/com/fizzgate/fizz/function/CodecFunc.java | 12 ++++++------ .../com/fizzgate/fizz/function/CodecFuncTests.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java index 8044e04..23553cc 100644 --- a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java +++ b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java @@ -189,27 +189,27 @@ public class CodecFunc implements IFunc { } } - public String hmacMd5(String secretKey, String data) { + public String hmacMd5(String data, String secretKey) { return new HmacUtils(HmacAlgorithms.HMAC_MD5, secretKey).hmacHex(data); } - public String hmacSha1(String secretKey, String data) { + public String hmacSha1(String data, String secretKey) { return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, secretKey).hmacHex(data); } - public String hmacSha224(String secretKey, String data) { + public String hmacSha224(String data, String secretKey) { return new HmacUtils(HmacAlgorithms.HMAC_SHA_224, secretKey).hmacHex(data); } - public String hmacSha256(String secretKey, String data) { + public String hmacSha256(String data, String secretKey) { return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(data); } - public String hmacSha384(String secretKey, String data) { + public String hmacSha384(String data, String secretKey) { return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, secretKey).hmacHex(data); } - public String hmacSha512(String secretKey, String data) { + public String hmacSha512(String data, String secretKey) { return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, secretKey).hmacHex(data); } diff --git a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java index 4c79872..0c1609b 100644 --- a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java +++ b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java @@ -125,7 +125,7 @@ class CodecFuncTests { @Test void testHmacSha256() { - String funcExpression = "fn.codec.hmacSha256(\"635e8562b968bc05bb80cacf124ebd53285280ee6845df0000faa33acafc38f0\", \"12345678123456781234567812345678\")"; + String funcExpression = "fn.codec.hmacSha256(\"12345678123456781234567812345678\", \"635e8562b968bc05bb80cacf124ebd53285280ee6845df0000faa33acafc38f0\")"; Object result = FuncExecutor.getInstance().exec(null, funcExpression); assertEquals("c61be0237ec186df1c5f51425e607093b260a76e5de43a62cb3e821103303990", result.toString()); } From 491f6d399afd85e0ad20d09384b1894109f35330 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Sat, 4 Mar 2023 11:43:05 +0800 Subject: [PATCH 4/8] Fix flow control problem --- fizz-bootstrap/pom.xml | 4 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- .../filter/FilterExceptionHandlerConfig.java | 14 +- .../com/fizzgate/filter/FizzLogFilter.java | 4 +- .../fizzgate/filter/FlowControlFilter.java | 126 +++++++++--------- .../com/fizzgate/filter/PreprocessFilter.java | 19 ++- .../java/com/fizzgate/filter/RouteFilter.java | 106 +++++++-------- .../plugin/FizzPluginFilterChain.java | 12 ++ .../com/fizzgate/plugin/PluginFilter.java | 11 +- .../plugin/auth/AuthPluginFilter.java | 1 - .../plugin/requestbody/RequestBodyPlugin.java | 23 +++- .../plugin/stat/StatPluginFilter.java | 1 + .../com/fizzgate/proxy/FizzWebClient.java | 10 +- .../java/com/fizzgate/stats/FlowStat.java | 32 ++--- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 38 +++++- 18 files changed, 231 insertions(+), 178 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index f30a1a4..b95c7f0 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -6,7 +6,7 @@ fizz-gateway-community com.fizzgate - 2.7.1 + 2.7.2-SNAPSHOT ../pom.xml @@ -18,7 +18,7 @@ Dragonfruit-SR3 Dysprosium-SR25 5.3.7.RELEASE - 4.1.89.Final + 4.1.90.Final 4.4.16 2.17.2 1.7.36 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 9953932..e3e6140 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.1 + 2.7.2-SNAPSHOT ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index d4278cd..4f67eed 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.1 + 2.7.2-SNAPSHOT ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java b/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java index c71bf75..e773488 100644 --- a/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java +++ b/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java @@ -56,13 +56,19 @@ public class FilterExceptionHandlerConfig { public static class FilterExceptionHandler implements WebExceptionHandler { - private static final Logger log = LoggerFactory.getLogger(FilterExceptionHandler.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FilterExceptionHandler.class); private static final String filterExceptionHandler = "filterExceptionHandler"; @Override public Mono handle(ServerWebExchange exchange, Throwable t) { exchange.getAttributes().put(WebUtils.ORIGINAL_ERROR, t); String traceId = WebUtils.getTraceId(exchange); + + if (LOGGER.isDebugEnabled()) { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + LOGGER.debug(Consts.S.EMPTY, t); + } + ServerHttpResponse resp = exchange.getResponse(); if (SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) { if (t instanceof ResponseStatusException) { @@ -113,9 +119,8 @@ public class FilterExceptionHandlerConfig { if (t instanceof FizzRuntimeException) { FizzRuntimeException ex = (FizzRuntimeException) t; - // log.error(traceId + ' ' + tMsg, LogService.BIZ_ID, traceId, ex); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); - log.error(traceId + ' ' + tMsg, ex); + LOGGER.error(tMsg, ex); respHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); RespEntity rs = null; if (ex.getStepContext() != null && ex.getStepContext().returnContext()) { @@ -132,9 +137,8 @@ public class FilterExceptionHandlerConfig { if (fc == null) { // t came from flow control filter StringBuilder b = ThreadContext.getStringBuilder(); WebUtils.request2stringBuilder(exchange, b); - // log.error(b.toString(), LogService.BIZ_ID, traceId, t); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); - log.error(b.toString(), t); + LOGGER.error(b.toString(), t); String s = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(), tMsg, traceId); respHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); vm = resp.writeWith(Mono.just(resp.bufferFactory().wrap(s.getBytes()))); diff --git a/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java index 9878ce4..9fa7e0b 100644 --- a/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java @@ -51,14 +51,14 @@ public class FizzLogFilter implements WebFilter { long start = System.currentTimeMillis(); return chain.filter(exchange).doFinally( (c) -> { - if (log.isInfoEnabled()) { + if (log.isDebugEnabled()) { StringBuilder b = ThreadContext.getStringBuilder(); WebUtils.request2stringBuilder(exchange, b); b.append(resp).append(exchange.getResponse().getStatusCode()) .append(in) .append(System.currentTimeMillis() - start); // log.info(b.toString(), LogService.BIZ_ID, WebUtils.getTraceId(exchange)); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, WebUtils.getTraceId(exchange)); - log.info(b.toString()); + log.debug(b.toString()); } } ); diff --git a/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java index 6446d11..8eb7bd3 100644 --- a/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java @@ -17,19 +17,6 @@ package com.fizzgate.filter; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilterChain; - import com.fizzgate.config.SystemConfig; import com.fizzgate.monitor.FizzMonitorService; import com.fizzgate.plugin.auth.ApiConfigService; @@ -44,7 +31,19 @@ import com.fizzgate.stats.degrade.DegradeRule; import com.fizzgate.stats.ratelimit.ResourceRateLimitConfig; import com.fizzgate.stats.ratelimit.ResourceRateLimitConfigService; import com.fizzgate.util.*; - +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; import reactor.core.publisher.SignalType; @@ -63,7 +62,7 @@ public class FlowControlFilter extends FizzWebFilter { public static final String FLOW_CONTROL_FILTER = "flowControlFilter"; - private static final Logger log = LoggerFactory.getLogger(FlowControlFilter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FlowControlFilter.class); private static final String admin = "admin"; @@ -160,7 +159,6 @@ public class FlowControlFilter extends FizzWebFilter { if (!favReq && flowControlFilterProperties.isFlowControl() && !adminReq && !proxyTestReq && !fizzApiReq) { String traceId = WebUtils.getTraceId(exchange); - // LogService.setBizId(traceId); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); if (!apiConfigService.serviceConfigMap.containsKey(service)) { String json = WebUtils.jsonRespBody(HttpStatus.FORBIDDEN.value(), "no service " + service + " in flow config", traceId); @@ -178,12 +176,10 @@ public class FlowControlFilter extends FizzWebFilter { }); if (result != null && !result.isSuccess()) { - long currentTimeMillis = System.currentTimeMillis(); String blockedResourceId = result.getBlockedResourceId(); if (BlockType.CIRCUIT_BREAK == result.getBlockType()) { fizzMonitorService.alarm(service, path, FizzMonitorService.CIRCUIT_BREAK_ALARM, null); - // log.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId, LogService.BIZ_ID, traceId); - log.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId); + LOGGER.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId); String responseContentType = flowControlFilterProperties.getDegradeDefaultResponseContentType(); String responseContent = flowControlFilterProperties.getDegradeDefaultResponseContent(); @@ -214,12 +210,10 @@ public class FlowControlFilter extends FizzWebFilter { } else { if (BlockType.CONCURRENT_REQUEST == result.getBlockType()) { fizzMonitorService.alarm(service, path, FizzMonitorService.RATE_LIMIT_ALARM, concurrents); - // log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId, LogService.BIZ_ID, traceId); - log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId); + LOGGER.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId); } else { fizzMonitorService.alarm(service, path, FizzMonitorService.RATE_LIMIT_ALARM, qps); - // log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId, LogService.BIZ_ID, traceId); - log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId); + LOGGER.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId); } ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceIdUtils.NODE_RESOURCE); @@ -240,42 +234,50 @@ public class FlowControlFilter extends FizzWebFilter { return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rc.getBytes()))); } } else { - long start = System.currentTimeMillis(); - setTraceId(exchange); - String finalService = service; - String finalPath = path; - return chain.filter(exchange).doFinally(s -> { - long rt = System.currentTimeMillis() - start; - CircuitBreaker cb = exchange.getAttribute(CircuitBreaker.DETECT_REQUEST); - HttpStatus statusCode = exchange.getResponse().getStatusCode(); - Throwable t = exchange.getAttribute(WebUtils.ORIGINAL_ERROR); - if (t instanceof TimeoutException) { - statusCode = HttpStatus.GATEWAY_TIMEOUT; - } - // if (s == SignalType.ON_ERROR || statusCode.is4xxClientError() || statusCode.is5xxServerError()) { - if (s == SignalType.ON_ERROR || statusCode.is5xxServerError()) { - flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false, statusCode); - if (cb != null) { - cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.OPEN, currentTimeSlot, flowStat); - } - if (statusCode == HttpStatus.GATEWAY_TIMEOUT) { - fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.TIMEOUT_ALARM, t.getMessage()); - } else if (statusCode.is5xxServerError()) { - fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, String.valueOf(statusCode.value())); - } else if (s == SignalType.ON_ERROR && t != null) { - fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, t.getMessage()); - } - } else { - flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true, statusCode); - if (cb != null) { - cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.CLOSED, currentTimeSlot, flowStat); - } - } - }); + long start = System.currentTimeMillis(); + String finalService = service; + String finalPath = path; + return chain.filter(exchange).doFinally(s -> { + + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + long rt = System.currentTimeMillis() - start; + CircuitBreaker cb = exchange.getAttribute(CircuitBreaker.DETECT_REQUEST); + HttpStatus statusCode = exchange.getResponse().getStatusCode(); + Throwable t = exchange.getAttribute(WebUtils.ORIGINAL_ERROR); + if (t instanceof TimeoutException) { + statusCode = HttpStatus.GATEWAY_TIMEOUT; + } + + if (s == SignalType.ON_ERROR || statusCode.is5xxServerError()) { + flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false, statusCode); + if (cb != null) { + cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.OPEN, currentTimeSlot, flowStat); + } + if (statusCode == HttpStatus.GATEWAY_TIMEOUT) { + fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.TIMEOUT_ALARM, t.getMessage()); + } else if (statusCode.is5xxServerError()) { + fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, String.valueOf(statusCode.value())); + } else if (s == SignalType.ON_ERROR && t != null) { + fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, t.getMessage()); + } + } else { + flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true, statusCode); + if (cb != null) { + cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.CLOSED, currentTimeSlot, flowStat); + } + } + + if (s == SignalType.CANCEL) { + ClientResponse remoteResp = exchange.getAttribute("remoteResp"); + if (remoteResp != null) { + remoteResp.bodyToMono(Void.class).subscribe(); + LOGGER.warn("client cancel, and dispose remote response"); + } + } + }); } } - // setTraceId(exchange); return chain.filter(exchange); } @@ -340,15 +342,15 @@ public class FlowControlFilter extends FizzWebFilter { check = true; } } - if (log.isDebugEnabled()) { - log.debug("getResourceConfigItselfAndParents:\n" + JacksonUtils.writeValueAsString(rc) + '\n' + JacksonUtils.writeValueAsString(result)); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("getResourceConfigItselfAndParents:\n" + JacksonUtils.writeValueAsString(rc) + '\n' + JacksonUtils.writeValueAsString(result)); } return result; } private List getFlowControlConfigs(String app, String ip, String node, String service, String path) { - if (log.isDebugEnabled()) { - log.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path); } boolean hasHost = (StringUtils.isNotBlank(node) && !node.equals(ResourceIdUtils.NODE)); int sz = hasHost ? 10 : 9; @@ -377,8 +379,8 @@ public class FlowControlFilter extends FizzWebFilter { checkRateLimitConfigAndAddTo(resourceConfigs, b, null, ip, null, service, path, null); } - if (log.isDebugEnabled()) { - log.debug("resource configs: " + JacksonUtils.writeValueAsString(resourceConfigs)); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("resource configs: " + JacksonUtils.writeValueAsString(resourceConfigs)); } return resourceConfigs; } diff --git a/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java index 0a30972..1060b32 100644 --- a/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java @@ -17,6 +17,7 @@ package com.fizzgate.filter; +import com.fizzgate.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; @@ -35,10 +36,6 @@ import com.fizzgate.plugin.auth.GatewayGroup; import com.fizzgate.plugin.auth.GatewayGroupService; import com.fizzgate.plugin.stat.StatPluginFilter; import com.fizzgate.proxy.Route; -import com.fizzgate.util.ReactorUtils; -import com.fizzgate.util.Result; -import com.fizzgate.util.ThreadContext; -import com.fizzgate.util.WebUtils; import reactor.core.publisher.Mono; @@ -54,7 +51,7 @@ import java.util.function.Function; @Order(10) public class PreprocessFilter extends FizzWebFilter { - private static final Logger log = LoggerFactory.getLogger(PreprocessFilter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(PreprocessFilter.class); public static final String PREPROCESS_FILTER = "preprocessFilter"; @@ -72,6 +69,12 @@ public class PreprocessFilter extends FizzWebFilter { @Override public Mono doFilter(ServerWebExchange exchange, WebFilterChain chain) { + String traceId = WebUtils.getTraceId(exchange); + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("preprocess filter start"); + } + Map fc = new HashMap<>(); fc.put(WebUtils.PREV_FILTER_RESULT, succFr); Map appendHdrs = new HashMap<>(8); Map eas = exchange.getAttributes(); eas.put(WebUtils.FILTER_CONTEXT, fc); @@ -85,8 +88,14 @@ public class PreprocessFilter extends FizzWebFilter { .thenReturn(ReactorUtils.Void) .flatMap( v -> { + + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + Result auth = (Result) WebUtils.getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT); if (auth.code == Result.FAIL) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("preprocess filter end 403"); + } return WebUtils.responseError(exchange, HttpStatus.FORBIDDEN.value(), auth.msg); } ApiConfig ac = auth.data; diff --git a/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java index 65d9863..8ea9fdd 100644 --- a/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java @@ -17,11 +17,22 @@ package com.fizzgate.filter; +import com.fizzgate.config.SystemConfig; +import com.fizzgate.plugin.auth.ApiConfig; +import com.fizzgate.proxy.FizzWebClient; +import com.fizzgate.proxy.Route; +import com.fizzgate.proxy.dubbo.ApacheDubboGenericService; +import com.fizzgate.proxy.dubbo.DubboInterfaceDeclaration; +import com.fizzgate.service_registry.RegistryCenterService; +import com.fizzgate.stats.FlowStat; +import com.fizzgate.stats.ResourceConfig; +import com.fizzgate.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -32,22 +43,13 @@ import org.springframework.web.reactive.function.BodyExtractors; import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; - -import com.fizzgate.config.SystemConfig; -import com.fizzgate.plugin.auth.ApiConfig; -import com.fizzgate.proxy.FizzWebClient; -import com.fizzgate.proxy.Route; -import com.fizzgate.proxy.dubbo.ApacheDubboGenericService; -import com.fizzgate.proxy.dubbo.DubboInterfaceDeclaration; -import com.fizzgate.service_registry.RegistryCenterService; -import com.fizzgate.util.*; - import reactor.core.publisher.Mono; import javax.annotation.Resource; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.function.Function; +import java.util.stream.Collectors; /** * @author hongqiaowei @@ -57,7 +59,7 @@ import java.util.function.Function; @Order(Ordered.LOWEST_PRECEDENCE) public class RouteFilter extends FizzWebFilter { - private static final Logger log = LoggerFactory.getLogger(RouteFilter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(RouteFilter.class); @Resource private FizzWebClient fizzWebClient; @@ -68,6 +70,9 @@ public class RouteFilter extends FizzWebFilter { @Resource private SystemConfig systemConfig; + @Resource + private FlowControlFilter flowControlFilter; + @Override public Mono doFilter(ServerWebExchange exchange, WebFilterChain chain) { @@ -77,16 +82,13 @@ public class RouteFilter extends FizzWebFilter { } else { Mono resp = WebUtils.getDirectResponse(exchange); if (resp == null) { // should not reach here - ServerHttpRequest clientReq = exchange.getRequest(); String traceId = WebUtils.getTraceId(exchange); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); String msg = traceId + ' ' + pfr.id + " fail"; if (pfr.cause == null) { - // log.error(msg, LogService.BIZ_ID, traceId); - log.error(msg); + LOGGER.error(msg); } else { - // log.error(msg, LogService.BIZ_ID, traceId, pfr.cause); - log.error(msg, pfr.cause); + LOGGER.error(msg, pfr.cause); } HttpStatus s = HttpStatus.INTERNAL_SERVER_ERROR; if (!SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) { @@ -101,8 +103,13 @@ public class RouteFilter extends FizzWebFilter { private Mono doFilter0(ServerWebExchange exchange, WebFilterChain chain) { - ServerHttpRequest req = exchange.getRequest(); String traceId = WebUtils.getTraceId(exchange); + if (LOGGER.isDebugEnabled()) { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + LOGGER.debug("route filter start"); + } + + ServerHttpRequest req = exchange.getRequest(); Route route = exchange.getAttribute(WebUtils.ROUTE); HttpHeaders hdrs = null; @@ -112,32 +119,17 @@ public class RouteFilter extends FizzWebFilter { } if (route == null) { - /*String pathQuery = WebUtils.getClientReqPathQuery(exchange); - return fizzWebClient.send2service(traceId, req.getMethod(), WebUtils.getClientService(exchange), pathQuery, hdrs, req.getBody(), 0, 0, 0) - .flatMap(genServerResponse(exchange));*/ - Map.Entry> pathQueryTemplate = WebUtils.getClientReqPathQueryTemplate(exchange).entrySet().iterator().next(); return fizzWebClient.send2service(traceId, req.getMethod(), WebUtils.getClientService(exchange), pathQueryTemplate.getKey(), hdrs, req.getBody(), 0, 0, 0, pathQueryTemplate.getValue().toArray(new String[0])) .flatMap(genServerResponse(exchange)); } else if (route.type == ApiConfig.Type.SERVICE_DISCOVERY) { - /*String pathQuery = getBackendPathQuery(req, route); - String svc = RegistryCenterService.getServiceNameSpace(route.registryCenter, route.backendService); - return fizzWebClient.send2service(traceId, route.method, svc, pathQuery, hdrs, req.getBody(), route.timeout, route.retryCount, route.retryInterval) - .flatMap(genServerResponse(exchange));*/ - Map.Entry> pathQueryTemplate = getBackendPathQueryTemplate(req, route).entrySet().iterator().next(); String svc = RegistryCenterService.getServiceNameSpace(route.registryCenter, route.backendService); return fizzWebClient.send2service(traceId, route.method, svc, pathQueryTemplate.getKey(), hdrs, req.getBody(), route.timeout, route.retryCount, route.retryInterval, pathQueryTemplate.getValue().toArray(new String[0])) .flatMap(genServerResponse(exchange)); } else if (route.type == ApiConfig.Type.REVERSE_PROXY) { - /*String uri = ThreadContext.getStringBuilder().append(route.nextHttpHostPort) - .append(getBackendPathQuery(req, route)) - .toString(); - return fizzWebClient.send(traceId, route.method, uri, hdrs, req.getBody(), route.timeout, route.retryCount, route.retryInterval) - .flatMap(genServerResponse(exchange));*/ - Map.Entry> pathQueryTemplate = getBackendPathQueryTemplate(req, route).entrySet().iterator().next(); String uri = ThreadContext.getStringBuilder().append(route.nextHttpHostPort) .append(pathQueryTemplate.getKey()) @@ -150,20 +142,6 @@ public class RouteFilter extends FizzWebFilter { } } - private String getBackendPathQuery(ServerHttpRequest request, Route route) { - String qry = route.query; - if (qry == null) { - MultiValueMap queryParams = request.getQueryParams(); - if (queryParams.isEmpty()) { - return route.backendPath; - } else { - return route.backendPath + Consts.S.QUESTION + WebUtils.toQueryString(queryParams); - } - } else { - return route.backendPath + Consts.S.QUESTION + qry; - } - } - private Map> getBackendPathQueryTemplate(ServerHttpRequest request, Route route) { String qry = route.query; if (qry == null) { @@ -183,6 +161,7 @@ public class RouteFilter extends FizzWebFilter { private Function> genServerResponse(ServerWebExchange exchange) { return remoteResp -> { + String traceId = WebUtils.getTraceId(exchange); ServerHttpResponse clientResp = exchange.getResponse(); clientResp.setStatusCode(remoteResp.statusCode()); HttpHeaders clientRespHeaders = clientResp.getHeaders(); @@ -203,24 +182,36 @@ public class RouteFilter extends FizzWebFilter { } } ); - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { StringBuilder b = ThreadContext.getStringBuilder(); - String traceId = WebUtils.getTraceId(exchange); WebUtils.response2stringBuilder(traceId, remoteResp, b); - // log.debug(b.toString(), LogService.BIZ_ID, traceId); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); - log.debug(b.toString()); + LOGGER.debug(b.toString()); } return clientResp.writeWith(remoteResp.body(BodyExtractors.toDataBuffers())) - .doOnError(throwable -> cleanup(remoteResp)).doOnCancel(() -> cleanup(remoteResp)); + .doOnError( + t -> { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + exchange.getAttributes().put("remoteResp", remoteResp); + LOGGER.error("response client error", t); + } + ) + .doOnCancel( + () -> { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + exchange.getAttributes().put("remoteResp", remoteResp); + LOGGER.error("client signal cancel"); + // cleanup(remoteResp); + } + ); }; } - private void cleanup(ClientResponse clientResponse) { - if (clientResponse != null) { - clientResponse.bodyToMono(Void.class).subscribe(); - } - } + // private void cleanup(ClientResponse clientResponse) { + // if (clientResponse != null) { + // clientResponse.bodyToMono(Void.class).subscribe(); + // } + // } private Mono dubboRpc(ServerWebExchange exchange, Route route) { final String[] ls = {null}; @@ -272,9 +263,8 @@ public class RouteFilter extends FizzWebFilter { if (ls[0] != null) { b.append('\n').append(ls[0]); } - // log.error(b.toString(), LogService.BIZ_ID, WebUtils.getTraceId(exchange), t); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, WebUtils.getTraceId(exchange)); - log.error(b.toString(), t); + LOGGER.error(b.toString(), t); } ) ; diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java b/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java index ff50658..9fc6995 100644 --- a/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java +++ b/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java @@ -17,6 +17,9 @@ package com.fizzgate.plugin; +import com.fizzgate.util.Consts; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; @@ -38,6 +41,8 @@ import java.util.Map; public final class FizzPluginFilterChain { + private static final Logger LOGGER = LoggerFactory.getLogger(FizzPluginFilterChain.class); + private static final String pluginConfigsIt = "pcsit@"; public static final String WEB_FILTER_CHAIN = "wfc@"; @@ -62,6 +67,13 @@ public final class FizzPluginFilterChain { if (it.hasNext()) { PluginConfig pc = it.next(); FizzPluginFilter pf = Fizz.context.getBean(pc.plugin, FizzPluginFilter.class); + + String traceId = WebUtils.getTraceId(exchange); + if (LOGGER.isDebugEnabled()) { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + LOGGER.debug("{} start", pc.plugin); + } + Mono m = pf.filter(exchange, pc.config); if (pf instanceof PluginFilter) { boolean f = false; diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java b/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java index de70d66..2665019 100644 --- a/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java @@ -43,7 +43,7 @@ import java.util.Map; @Deprecated public abstract class PluginFilter implements FizzPluginFilter { - private static final Logger log = LoggerFactory.getLogger(PluginFilter.class); + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); @Override public Mono filter(ServerWebExchange exchange, Map config) { @@ -55,9 +55,8 @@ public abstract class PluginFilter implements FizzPluginFilter { FilterResult pfr = WebUtils.getPrevFilterResult(exchange); String traceId = WebUtils.getTraceId(exchange); ThreadContext.put(Consts.TRACE_ID, traceId); - if (log.isDebugEnabled()) { - // log.debug(traceId + ' ' + this + ": " + pfr.id + " execute " + (pfr.success ? "success" : "fail"), LogService.BIZ_ID, traceId); - log.debug(traceId + ' ' + this + ": " + pfr.id + " execute " + (pfr.success ? "success" : "fail")); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("{} execute {}", pfr.id, pfr.success ? "success" : "fail"); } if (pfr.success) { return doFilter(exchange, config, fixedConfig); @@ -65,9 +64,9 @@ public abstract class PluginFilter implements FizzPluginFilter { if (WebUtils.getDirectResponse(exchange) == null) { // should not reach here String msg = traceId + ' ' + pfr.id + " fail"; if (pfr.cause == null) { - log.error(msg); + LOGGER.error(msg); } else { - log.error(msg, pfr.cause); + LOGGER.error(msg, pfr.cause); } HttpStatus s = HttpStatus.OK; if (SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) { diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java b/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java index 87312ca..1048548 100644 --- a/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java @@ -56,7 +56,6 @@ public class AuthPluginFilter extends PluginFilter { r -> { if (log.isDebugEnabled()) { String traceId = WebUtils.getTraceId(exchange); - // log.debug("{} req auth: {}", traceId, r, LogService.BIZ_ID, traceId); ThreadContext.put(Consts.TRACE_ID, traceId); log.debug("{} req auth: {}", traceId, r); } diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java b/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java index 542b034..2a53c12 100644 --- a/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java +++ b/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java @@ -46,13 +46,19 @@ import java.util.Map; @Component(RequestBodyPlugin.REQUEST_BODY_PLUGIN) public class RequestBodyPlugin implements FizzPluginFilter { - private static final Logger log = LoggerFactory.getLogger(RequestBodyPlugin.class); + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); public static final String REQUEST_BODY_PLUGIN = "requestBodyPlugin"; @Override public Mono filter(ServerWebExchange exchange, Map config) { + // String traceId = WebUtils.getTraceId(exchange); + // if (LOGGER.isDebugEnabled()) { + // org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + // LOGGER.debug("{} start", getClass().getSimpleName()); + // } + ServerHttpRequest req = exchange.getRequest(); if (req instanceof FizzServerHttpRequestDecorator) { return doFilter(exchange, config); @@ -76,18 +82,21 @@ public class RequestBodyPlugin implements FizzPluginFilter { if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) { newExchange = new FizzServerWebExchangeDecorator(mutatedExchange); } - if (log.isDebugEnabled()) { - String traceId = WebUtils.getTraceId(exchange); - // log.debug("{} request is decorated", traceId, LogService.BIZ_ID, traceId); - ThreadContext.put(Consts.TRACE_ID, traceId); - log.debug("{} request is decorated", traceId); - } + // if (LOGGER.isDebugEnabled()) { + // ThreadContext.put(Consts.TRACE_ID, traceId); + // LOGGER.debug("{} request is decorated", traceId); + // } return doFilter(newExchange, config); } ); } public Mono doFilter(ServerWebExchange exchange, Map config) { + String traceId = WebUtils.getTraceId(exchange); + if (LOGGER.isDebugEnabled()) { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); + LOGGER.debug("{} end", getClass().getSimpleName()); + } return FizzPluginFilterChain.next(exchange); } } diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java b/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java index e5ed774..c12a54f 100644 --- a/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java +++ b/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java @@ -90,6 +90,7 @@ public class StatPluginFilter extends PluginFilter { accessStat.reqTime = System.currentTimeMillis(); accessStat.reqs++; if (LOGGER.isDebugEnabled()) { + org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, WebUtils.getTraceId(exchange)); LOGGER.debug("update access stat: {}, which request at {}", accessStat, DateTimeUtils.convert(accessStat.reqTime, Consts.DP.DP19)); } } diff --git a/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java b/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java index a29fc01..a430b74 100644 --- a/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java +++ b/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java @@ -220,7 +220,6 @@ public class FizzWebClient { if (log.isDebugEnabled()) { StringBuilder b = ThreadContext.getStringBuilder(); WebUtils.request2stringBuilder(traceId, method, uri, headers, null, b); - // log.debug(b.toString(), LogService.BIZ_ID, traceId); org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId); log.debug(b.toString()); } @@ -243,10 +242,6 @@ public class FizzWebClient { } setHostHeader(uri, hdrs); if (systemConfig.isFizzWebClientXForwardedForEnable()) { - List values = hdrs.get(X_FORWARDED_FOR); - /* if (CollectionUtils.isEmpty(values)) { - hdrs.add(X_FORWARDED_FOR, WebUtils.getOriginIp(null)); - } */ if (systemConfig.isFizzWebClientXForwardedForAppendGatewayIp()) { hdrs.add(X_FORWARDED_FOR, NetworkUtils.getServerIp()); } @@ -269,8 +264,9 @@ public class FizzWebClient { Mono cr = req.exchange(); if (timeout == 0) { - if (systemConfig.getRouteTimeout() != 0) { - timeout = systemConfig.getRouteTimeout(); + long systemConfigRouteTimeout = systemConfig.getRouteTimeout(); + if (systemConfigRouteTimeout != 0) { + timeout = systemConfigRouteTimeout; } } if (timeout > 0) { diff --git a/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java b/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java index 16417ec..919177a 100644 --- a/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java +++ b/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java @@ -17,8 +17,20 @@ package com.fizzgate.stats; -import java.util.*; +import com.fizzgate.stats.circuitbreaker.CircuitBreakManager; +import com.fizzgate.stats.circuitbreaker.CircuitBreaker; +import com.fizzgate.util.Consts; +import com.fizzgate.util.ResourceIdUtils; +import com.fizzgate.util.WebUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ServerWebExchange; + +import java.util.ArrayList; +import java.util.List; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; @@ -26,17 +38,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.BiFunction; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.http.HttpStatus; -import org.springframework.web.server.ServerWebExchange; - -import com.fizzgate.stats.circuitbreaker.CircuitBreakManager; -import com.fizzgate.stats.circuitbreaker.CircuitBreaker; -import com.fizzgate.util.ResourceIdUtils; -import com.fizzgate.util.WebUtils; +import java.util.stream.Collectors; /** * Flow Statistic @@ -524,7 +526,7 @@ public class FlowStat { long slotInterval = slotIntervalInSec * 1000; if (resourceId == null) { - Set> entrys = resourceStats.entrySet(); + Set> entrys = resourceStats.entrySet(); for (Entry entry : entrys) { String rid = entry.getKey(); ResourceTimeWindowStat resourceWin = new ResourceTimeWindowStat(rid); @@ -585,7 +587,7 @@ public class FlowStat { } }*/ for (long i = lastSlotId; i < slotId;) { - Set> entrys = stat.resourceStats.entrySet(); + Set> entrys = stat.resourceStats.entrySet(); for (Entry entry : entrys) { String resourceId = entry.getKey(); ConcurrentMap timeSlots = entry.getValue().getTimeSlots(); @@ -649,7 +651,7 @@ public class FlowStat { long curTimeSlotId = stat.currentTimeSlotId(); if (lastTimeSlotId == null || lastTimeSlotId.longValue() != curTimeSlotId) { // log.debug("PeakConcurrentJob start"); - Set> entrys = stat.resourceStats.entrySet(); + Set> entrys = stat.resourceStats.entrySet(); for (Entry entry : entrys) { String resource = entry.getKey(); // log.debug("PeakConcurrentJob: resourceId={} slotId=={}", resourceId, diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 1c192eb..52ec30d 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.1 + 2.7.2-SNAPSHOT ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 6cae080..eecfae5 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.1 + 2.7.2-SNAPSHOT ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 142c19f..121ca24 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ Dysprosium-SR25 5.3.7.RELEASE 2.2.7.RELEASE - 4.1.89.Final + 4.1.90.Final 4.4.16 2.17.2 1.7.36 @@ -38,7 +38,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.7.1 + 2.7.2-SNAPSHOT pom fizz-common @@ -418,7 +418,7 @@ io.netty - netty-tcnative + netty-tcnative-classes ${netty-tcnative.version} @@ -428,7 +428,37 @@ io.netty - netty-tcnative-classes + netty-tcnative-boringssl-static + ${netty-tcnative.version} + linux-x86_64 + + + io.netty + netty-tcnative-boringssl-static + ${netty-tcnative.version} + linux-aarch_64 + + + io.netty + netty-tcnative-boringssl-static + ${netty-tcnative.version} + osx-x86_64 + + + io.netty + netty-tcnative-boringssl-static + ${netty-tcnative.version} + osx-aarch_64 + + + io.netty + netty-tcnative-boringssl-static + ${netty-tcnative.version} + windows-x86_64 + + + io.netty + netty-tcnative ${netty-tcnative.version} From 97b4785485030ddf90b7fbf3e6c5d03dbe84f0b5 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Sat, 25 Mar 2023 11:03:18 +0800 Subject: [PATCH 5/8] Upgrade spring Framework to 5.2.23 to fix cve-2023-20861 --- fizz-bootstrap/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index b95c7f0..1d22b7d 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -14,7 +14,7 @@ 2.2.13.RELEASE - 5.2.22.RELEASE + 5.2.23.RELEASE Dysprosium-SR25 5.3.7.RELEASE 2.2.7.RELEASE From c491f4a93c55fb3a332f876ef0f8f9a3458b2cab Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Tue, 4 Apr 2023 14:33:22 +0800 Subject: [PATCH 6/8] Ip plugin --- fizz-bootstrap/pom.xml | 2 +- .../java/com/fizzgate/plugin/ip/IpPlugin.java | 148 ++++++++++ .../com/fizzgate/plugin/ip/PluginConfig.java | 18 ++ .../com/fizzgate/plugin/ip/RouterConfig.java | 19 ++ .../fizzgate/plugin/ip/util/ConfigUtils.java | 36 +++ .../fizzgate/plugin/ip/util/IpMatchUtils.java | 271 ++++++++++++++++++ .../com/fizzgate/plugin/ip/util/IpUtils.java | 191 ++++++++++++ pom.xml | 2 +- 8 files changed, 685 insertions(+), 2 deletions(-) create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 1d22b7d..9e1fb67 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -18,7 +18,7 @@ Dragonfruit-SR3 Dysprosium-SR25 5.3.7.RELEASE - 4.1.90.Final + 4.1.91.Final 4.4.16 2.17.2 1.7.36 diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java new file mode 100644 index 0000000..1bb537d --- /dev/null +++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java @@ -0,0 +1,148 @@ +package com.fizzgate.plugin.ip; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fizzgate.plugin.ip.util.ConfigUtils; +import com.fizzgate.plugin.ip.util.IpMatchUtils; +import com.fizzgate.plugin.ip.util.IpUtils; +import com.fizzgate.plugin.FizzPluginFilter; +import com.fizzgate.plugin.FizzPluginFilterChain; +import com.fizzgate.plugin.auth.ApiConfig; +import com.fizzgate.plugin.auth.ApiConfigService; +import com.fizzgate.util.WebUtils; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import javax.annotation.Resource; +import java.net.SocketException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.fizzgate.plugin.ip.RouterConfig.FieldName.*; + +/** + * @author hua.huang + */ +@Slf4j +@Component(value = IpPlugin.PLUGIN_NAME) +public class IpPlugin implements FizzPluginFilter { + public static final String PLUGIN_NAME = "fizz_plugin_ip"; + @Resource + private ObjectMapper objectMapper; + @Resource + private ApiConfigService apiConfigService; + + @Override + @SuppressWarnings("unchecked") + public Mono filter(ServerWebExchange exchange, Map config) { + RouterConfig routerConfig = routerConfig(exchange, config); + List pluginConfigItemList = null;/* pluginConfig(exchange, config); */ + if (access(exchange, routerConfig, pluginConfigItemList)) { + log.trace("pass..."); + return FizzPluginFilterChain.next(exchange); + } + log.trace("forbidden!"); + HttpHeaders headers = new HttpHeaders(); + headers.set(HttpHeaders.CONTENT_TYPE, routerConfig.getErrorRespContentType()); + return WebUtils.buildDirectResponse(exchange, HttpStatus.FORBIDDEN, + headers, routerConfig.getErrorRespContent()); + } + + private boolean access(ServerWebExchange exchange, + RouterConfig routerConfig, List pluginConfigItemList) { + Set fixedWhiteIpSet = Sets.newHashSet(); + Set fixedBlackIpSet = Sets.newHashSet(); + ApiConfig apiConfig = apiConfig(exchange); + Set gatewayGroups = (apiConfig == null || apiConfig.gatewayGroups == null) ? Sets.newHashSet() : apiConfig.gatewayGroups; + /* if (!CollectionUtils.isEmpty(pluginConfigItemList)) { + for (PluginConfig.Item fixedConfigItem : pluginConfigItemList) { + if (gatewayGroups.contains(fixedConfigItem.getGwGroup())) { + fixedWhiteIpSet.addAll(IpMatchUtils.ipConfigList(fixedConfigItem.getWhiteIp())); + fixedBlackIpSet.addAll(IpMatchUtils.ipConfigList(fixedConfigItem.getBlackIp())); + } + } + } */ + Set whiteIpSet = ConfigUtils.string2set(routerConfig.getWhiteIp()); + Set blackIpSet = ConfigUtils.string2set(routerConfig.getBlackIp()); + + String ip = null; + try { + ip = IpUtils.getServerHttpRequestIp(exchange.getRequest()); + } catch (SocketException e) { + log.warn(e.getMessage(), e); + } + log.trace("clientIp:{}, fixedWhiteIpSet:{}, fixedBlackIpSet:{}, whiteIpSet:{}, blackIpSet:{}", + ip, fixedWhiteIpSet, fixedBlackIpSet, whiteIpSet, blackIpSet); + // 未获取到client ip,返回false + if (StringUtils.isBlank(ip)) { + return false; + } + + // 优先匹配路由级别配置,然后再匹配插件级别配置 + + // 路由级别::白名单匹配到就直接返回true + if (IpMatchUtils.match(ip, whiteIpSet)) { + return true; + } + // 路由级别::黑名单匹配到就直接返回false + if (IpMatchUtils.match(ip, blackIpSet)) { + return false; + } + // 插件级别::白名单匹配到就直接返回true + /* if (IpMatchUtils.match(ip, fixedWhiteIpSet)) { + return true; + } */ + // 插件级别::黑名单匹配到就直接返回false + /* if (IpMatchUtils.match(ip, fixedBlackIpSet)) { + return false; + } */ + // 路由级别和插件级别都没匹配到 + if (CollectionUtils.isEmpty(whiteIpSet) /* || CollectionUtils.isEmpty(fixedWhiteIpSet) */) { + // 都没有配置白名单,默认返回true + return true; + } else { + return false; + } + } + + private RouterConfig routerConfig(ServerWebExchange exchange, Map config) { + RouterConfig routerConfig = new RouterConfig(); + routerConfig.setErrorRespContentType((String) config.getOrDefault(ERROR_RESP_CONTENT_TYPE + , routerConfig.getErrorRespContentType())); + routerConfig.setErrorRespContent((String) config.getOrDefault(ERROR_RESP_CONTENT + , routerConfig.getErrorRespContent())); + routerConfig.setWhiteIp((String) config.getOrDefault(WHITE_IP, StringUtils.EMPTY)); + routerConfig.setBlackIp((String) config.getOrDefault(BLACK_IP, StringUtils.EMPTY)); + return routerConfig; + } + + private List pluginConfig(ServerWebExchange exchange, Map config) { + String fixedConfig = (String) config.get(com.fizzgate.plugin.PluginConfig.CUSTOM_CONFIG); + try { + PluginConfig pluginConfig = objectMapper.readValue(fixedConfig, PluginConfig.class); + if (pluginConfig != null && pluginConfig.getConfigs() != null) { + return pluginConfig.getConfigs(); + } + } catch (JsonProcessingException e) { + throw new RuntimeException(e.getMessage(), e); + } + return Lists.newArrayList(); + } + + private ApiConfig apiConfig(ServerWebExchange exchange) { + ServerHttpRequest req = exchange.getRequest(); + return apiConfigService.getApiConfig(WebUtils.getAppId(exchange), + WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange)); + } + +} diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java new file mode 100644 index 0000000..c642c19 --- /dev/null +++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java @@ -0,0 +1,18 @@ +package com.fizzgate.plugin.ip; + +import com.google.common.collect.Lists; +import lombok.Data; + +import java.util.List; + +@Data +public class PluginConfig { + private List configs = Lists.newArrayList(); + + @Data + public static class Item { + private String gwGroup; + private String whiteIp; + private String blackIp; + } +} diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java new file mode 100644 index 0000000..9db1741 --- /dev/null +++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java @@ -0,0 +1,19 @@ +package com.fizzgate.plugin.ip; + +import lombok.Data; +import org.springframework.http.MediaType; + +@Data +public class RouterConfig { + private String errorRespContentType = MediaType.APPLICATION_JSON_UTF8_VALUE; + private String errorRespContent = "{\"msg\":\"非法IP\",\"code\":-1}"; + private String whiteIp; + private String blackIp; + + public interface FieldName { + String ERROR_RESP_CONTENT_TYPE = "errorRespContentType"; + String ERROR_RESP_CONTENT = "errorRespContent"; + String WHITE_IP = "whiteIp"; + String BLACK_IP = "blackIp"; + } +} diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java new file mode 100644 index 0000000..a29d03a --- /dev/null +++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java @@ -0,0 +1,36 @@ +package com.fizzgate.plugin.ip.util; + +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; +import com.google.common.collect.Sets; +import org.apache.commons.lang3.StringUtils; + +import java.util.Set; +import java.util.stream.Collectors; + +public abstract class ConfigUtils { + public static final String DEFAULT_CHAR_MATCHER_ANY_OF = ",\n"; + + public static Set string2set(String strVal, String charMatcherAnyOf) { + Set finalSet = Sets.newHashSet(); + if (StringUtils.isBlank(strVal)) { + return finalSet; + } + charMatcherAnyOf = StringUtils.isBlank(charMatcherAnyOf) ? DEFAULT_CHAR_MATCHER_ANY_OF : charMatcherAnyOf; + Set set = Sets.newHashSet( + Splitter.on(CharMatcher.anyOf(charMatcherAnyOf)).trimResults().split(strVal)); + set = set.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet()); + for (String s : set) { + if (StringUtils.isBlank(s)) { + continue; + } + finalSet.add(StringUtils.trimToEmpty(s)); + } + return finalSet; + } + + public static Set string2set(String strVal) { + return string2set(strVal, DEFAULT_CHAR_MATCHER_ANY_OF); + } + +} diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java new file mode 100644 index 0000000..70124b6 --- /dev/null +++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java @@ -0,0 +1,271 @@ +package com.fizzgate.plugin.ip.util; + +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; +import com.google.common.collect.Sets; +import inet.ipaddr.AddressStringException; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * ipv4匹配工具 + */ +public final class IpMatchUtils { + // IP正则 + private static final Pattern IP_PATTERN = Pattern.compile( + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})"); + public static final String DEFAULT_ALLOW_ALL_FLAG = "*";// 允许所有ip标志位 + public static final String DEFAULT_DENY_ALL_FLAG = "0"; // 禁止所有ip标志位 + private static final String RANGE_SPLITTER = "-"; // ip范围分隔符 + + /** + * 根据IP白名单设置获取可用的IP列表 + */ + public static Set ipConfigList(String allowIp) { + // 拆分出白名单正则 + Set set = Sets.newHashSet(Splitter.on(CharMatcher.anyOf(",\n")).trimResults().split(allowIp)); + set = set.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet()); + return ipConfigList(Sets.newHashSet(set)); + } + + /** + * 根据IP白名单设置获取可用的IP列表 + */ + public static Set ipConfigList(Set allowIpList) { + Set ipList = new HashSet<>(allowIpList.size()); + for (String allow : allowIpList) { + if (allow.contains("*")) { // 处理通配符 * + String[] ips = allow.split("\\."); + String[] from = new String[]{"0", "0", "0", "0"}; + String[] end = new String[]{"255", "255", "255", "255"}; + List tem = new ArrayList<>(); + for (int i = 0; i < ips.length; i++) + if (ips[i].contains("*")) { + tem = complete(ips[i]); + from[i] = null; + end[i] = null; + } else { + from[i] = ips[i]; + end[i] = ips[i]; + } + + StringBuilder fromIP = new StringBuilder(); + StringBuilder endIP = new StringBuilder(); + for (int i = 0; i < 4; i++) { + if (from[i] != null) { + fromIP.append(from[i]).append("."); + endIP.append(end[i]).append("."); + } else { + fromIP.append("[*]."); + endIP.append("[*]."); + } + } + fromIP.deleteCharAt(fromIP.length() - 1); + endIP.deleteCharAt(endIP.length() - 1); + + for (String s : tem) { + String ip = fromIP.toString().replace("[*]", s.split(";")[0]) + RANGE_SPLITTER + + endIP.toString().replace("[*]", s.split(";")[1]); + if (validate(ip)) { + ipList.add(ip); + } + } + } else if (allow.contains("/")) { // 处理 网段 xxx.xxx.xxx./24 + ipList.add(allow); + } else { // 处理单个 ip 或者 范围 + if (validate(allow)) { + ipList.add(allow); + } + } + + } + + return ipList; + } + + /** + * 对单个IP节点进行范围限定 + * + * @param arg + * @return 返回限定后的IP范围,格式为List[10;19, 100;199] + */ + private static List complete(String arg) { + List com = new ArrayList<>(); + int len = arg.length(); + if (len == 1) { + com.add("0;255"); + } else if (len == 2) { + String s1 = complete(arg, 1); + if (s1 != null) { + com.add(s1); + } + String s2 = complete(arg, 2); + if (s2 != null) { + com.add(s2); + } + } else { + String s1 = complete(arg, 1); + if (s1 != null) { + com.add(s1); + } + } + return com; + } + + private static String complete(String arg, int length) { + String from = ""; + String end = ""; + if (length == 1) { + from = arg.replace("*", "0"); + end = arg.replace("*", "9"); + } else { + from = arg.replace("*", "00"); + end = arg.replace("*", "99"); + } + if (Integer.parseInt(from) > 255) { + return null; + } + if (Integer.parseInt(end) > 255) { + end = "255"; + } + return from + ";" + end; + } + + /** + * 在添加至白名单时进行格式校验 + */ + private static boolean validate(String ip) { + String[] temp = ip.split(RANGE_SPLITTER); + for (String s : temp) { + if (!IP_PATTERN.matcher(s).matches()) { + return false; + } + } + return true; + } + + /** + * 根据IP,及可用Ip列表来判断ip是否包含在白名单之中 + */ + public static boolean match(String ip, Set ipList) { + if (CollectionUtils.isEmpty(ipList)) { + return false; + } + if (ipList.contains(ip)) { + return true; + } + IPAddress ipAddress = null; + try { + ipAddress = new IPAddressString(ip).toAddress(); + } catch (AddressStringException e) { + throw new RuntimeException(e); + } + for (String allow : ipList) { + if (allow.contains(RANGE_SPLITTER)) { // 处理 类似 192.168.0.0-192.168.2.1 + String[] tempAllow = allow.split(RANGE_SPLITTER); + String[] from = tempAllow[0].split("\\."); + String[] end = tempAllow[1].split("\\."); + String[] tag = ip.split("\\."); + boolean check = true; + for (int i = 0; i < 4; i++) { // 对IP从左到右进行逐段匹配 + int s = Integer.parseInt(from[i]); + int t = Integer.parseInt(tag[i]); + int e = Integer.parseInt(end[i]); + if (!(s <= t && t <= e)) { + check = false; + break; + } + } + if (check) { + return true; + } + } else if (allow.contains("/")) { // 处理 网段 xxx.xxx.xxx./24 + int splitIndex = allow.indexOf("/"); + // 取出子网段 + String ipSegment = allow.substring(0, splitIndex); // 192.168.3.0 + // 子网数 + String netmask = allow.substring(splitIndex + 1); // 24 + // ip 转二进制 + long ipLong = ipToLong(ip); + // 子网二进制 + long maskLong = (2L << 32 - 1) - (2L << (32 - Integer.parseInt(netmask)) - 1); + // ip与和子网相与 得到 网络地址 + String calcSegment = longToIP(ipLong & maskLong); + // 如果计算得出网络地址和库中网络地址相同 则合法 + if (ipSegment.equals(calcSegment)) { + return true; + } + } else if (allow.contains("*")) { + IPAddress rangeAddress = new IPAddressString(allow).getAddress(); + if (rangeAddress.contains(ipAddress)) { + return true; + } + } + } + return false; + } + + /** + * 根据IP地址,及IP白名单设置规则判断IP是否包含在白名单 + */ + public static boolean match(String ip, String ipWhiteConfig) { + if (null == ip || "".equals(ip)) { + return false; + } + // ip格式不对 + if (!IP_PATTERN.matcher(ip).matches()) { + return false; + } + if (DEFAULT_ALLOW_ALL_FLAG.equals(ipWhiteConfig)) { + return true; + } + if (DEFAULT_DENY_ALL_FLAG.equals(ipWhiteConfig)) { + return false; + } + Set ipList = ipConfigList(ipWhiteConfig); + return match(ip, ipList); + } + + /** + * 将 127.0.0.1形式的IP地址 转换成 10进制整数形式 + */ + private static long ipToLong(String strIP) { + long[] ip = new long[4]; + // 先找到IP地址字符串中.的位置 + int position1 = strIP.indexOf("."); + int position2 = strIP.indexOf(".", position1 + 1); + int position3 = strIP.indexOf(".", position2 + 1); + // 将每个.之间的字符串转换成整型 + ip[0] = Long.parseLong(strIP.substring(0, position1)); + ip[1] = Long.parseLong(strIP.substring(position1 + 1, position2)); + ip[2] = Long.parseLong(strIP.substring(position2 + 1, position3)); + ip[3] = Long.parseLong(strIP.substring(position3 + 1)); + return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3]; + } + + /** + * 将 10进制整数形式 转换成 127.0.0.1形式的IP地址 + */ + private static String longToIP(long longIP) { + // 直接右移24位 + return "" + (longIP >>> 24) + + "." + + // 将高8位置0,然后右移16位 + ((longIP & 0x00FFFFFF) >>> 16) + + "." + + ((longIP & 0x0000FFFF) >>> 8) + + "." + + (longIP & 0x000000FF); + } + +} \ No newline at end of file diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java new file mode 100644 index 0000000..64917c7 --- /dev/null +++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java @@ -0,0 +1,191 @@ +package com.fizzgate.plugin.ip.util; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.server.reactive.ServerHttpRequest; + +import java.net.*; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author huahua + */ +public class IpUtils { + + /* + * 取所有IP段的私有IP段 + * A类 私有地址 10.0.0.0---10.255.255.255 保留地址 127.0.0.0---127.255.255.255 + * B类 私有地址 172.16.0.0-172.31.255.255 + * C类 私有地址 192.168.0.0-192.168.255.255 + * D类 地址不分网络地址和主机地址 + * E类 地址不分网络地址和主机地址 + */ + private static long + aBegin = ipToLong("10.0.0.0"), + aEnd = ipToLong("10.255.255.255"), + bBegin = ipToLong("172.16.0.0"), + bEnd = ipToLong("172.31.255.255"), + cBegin = ipToLong("192.168.0.0"), + cEnd = ipToLong("192.168.255.255"), + saveBegin = ipToLong("127.0.0.0"), + saveEnd = ipToLong("127.255.255.255"); + + // 跟IP有关需要做判断的header参数 + private static String + CLIENT_IP = "clientip", + X_FORWARDED_FOR = "x-forwarded-for", + PROXY_CLIENT_IP = "proxy-client-ip", + WL_PROXY_CLIENT_IP = "wl-proxy-client-ip"; + private static Set ipHeaderNames = Sets.newHashSet(CLIENT_IP, X_FORWARDED_FOR, PROXY_CLIENT_IP, WL_PROXY_CLIENT_IP); + + public static String getServerHttpRequestIp(ServerHttpRequest request) throws SocketException { + // 防止在header中的参数名有大小写之分,重新将需要处理的参数值和内容装填入Map中 + Map> ipHeaders = Maps.newHashMap(); + Set>> headers = request.getHeaders().entrySet(); + for (Map.Entry> header : headers) { + String name = header.getKey(); + String lowerCaseName = name.toLowerCase(); + if (ipHeaderNames.contains(lowerCaseName)) { + List values = Lists.newArrayList(); + for (String headerValue : header.getValue()) { + if (StringUtils.indexOf(headerValue, ",") >= 0) { + String[] headerValueArr = StringUtils.split(headerValue, ","); + if (headerValueArr.length > 0) { + for (String s : headerValueArr) { + values.add(StringUtils.trimToEmpty(s)); + } + } + } else { + values.add(headerValue); + } + } + ipHeaders.put(lowerCaseName, values); // 装填key和value + } + } + //取正确的IP + String ipAddress = null; + // 取clientip + List clientIpList = ipHeaders.get(CLIENT_IP); // 取clientip与client-ip有区别 + ipAddress = fetchPublicIp(clientIpList); + // 若clientip为空或者是内网IP则取x-forwarded-for + if (StringUtils.isBlank(ipAddress)) { + List xForwardedIpList = ipHeaders.get(X_FORWARDED_FOR); + ipAddress = fetchPublicIp(xForwardedIpList); + } + // 若x-forwarded-for为空则取proxy-client-ip + if (StringUtils.isBlank(ipAddress)) { + List proxyClientIpList = ipHeaders.get(PROXY_CLIENT_IP); + ipAddress = fetchPublicIp(proxyClientIpList); + } + // 若proxy-client-ip为空则取wl-proxy-client-ip + if (StringUtils.isBlank(ipAddress)) { + List wlProxyClientIpList = ipHeaders.get(WL_PROXY_CLIENT_IP); + ipAddress = fetchPublicIp(wlProxyClientIpList); + } + // 若wl-proxy-client-ip为空则取RemoteAddr + if (StringUtils.isBlank(ipAddress)) { + InetSocketAddress inetSocketAddress = request.getRemoteAddress(); + if (inetSocketAddress != null) { + InetAddress inetAddress = inetSocketAddress.getAddress(); + if (inetAddress instanceof Inet4Address) { + ipAddress = inetAddress.getHostAddress(); + } + } + if (StringUtils.equals(ipAddress, "127.0.0.1")) { + // 根据网卡取本机配置的IP + ipAddress = getLocalIp(); + } + } + return ipAddress; + } + + public static String getLocalIp() throws SocketException { + Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); + InetAddress ip; + while (allNetInterfaces.hasMoreElements()) { + NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement(); + Enumeration addresses = netInterface.getInetAddresses(); + while (addresses.hasMoreElements()) { + ip = (InetAddress) addresses.nextElement(); + if (ip instanceof Inet4Address) { + return ip.getHostAddress(); + } + } + } + return ""; + } + + public static long localIpNumber() throws SocketException { + return ipToLong(getLocalIp()); + } + + private static long ipToLong(String ipAddress) { + long result = 0L; + String[] ipAddressInArray = ipAddress.split("\\."); + if (ipAddressInArray.length != 4) { + return 0; + } + for (int i = 3; i >= 0; i--) { + long ip = 0; + try { + ip = Long.parseLong(ipAddressInArray[3 - i]); + } catch (NumberFormatException e) { + // ignore + } + result |= ip << (i * 8); + } + return result; + } + + public static String fetchPublicIp(List ipAddressList) { + String ipAddress = null; + if (ipAddressList == null || ipAddressList.size() <= 0) { + return ipAddress; + } + for (String ip : ipAddressList) { + long ipNum = ipToLong(ip); + if (isIpAddress(ip) + && !isInner(ipNum, aBegin, aEnd) + && !isInner(ipNum, bBegin, bEnd) + && !isInner(ipNum, cBegin, cEnd) + && !isInner(ipNum, saveBegin, saveEnd)) { + ipAddress = ip; + break; + } + } + return ipAddress; + } + + public static boolean isInnerIP(String ipAddress) { + long ipNum = ipToLong(ipAddress); + return isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || isInner(ipNum, saveBegin, saveEnd); + } + + private static boolean isInner(long userIp, long begin, long end) { + return (userIp >= begin) && (userIp <= end); + } + + /** + * 检验是否是合法的IP地址 + * + * @param address String IP地址 + * @return boolean IP地址是否合法 + */ + public static boolean isIpAddress(String address) { + if (StringUtils.isEmpty(address)) { + return false; + } + String regex = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}"; + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(address); + return m.matches(); + } + +} diff --git a/pom.xml b/pom.xml index a6e3601..5309cc0 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ Dysprosium-SR25 5.3.7.RELEASE 2.2.7.RELEASE - 4.1.90.Final + 4.1.91.Final 4.4.16 2.17.2 1.7.36 From 96bfe4defcfbf4be3498d5dbff1874c25cce30f7 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Mon, 10 Apr 2023 17:54:01 +0800 Subject: [PATCH 7/8] correct comment --- fizz-bootstrap/js/common.js | 4 ++-- fizz-bootstrap/src/main/resources/js/common.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fizz-bootstrap/js/common.js b/fizz-bootstrap/js/common.js index cccb334..c8eb437 100644 --- a/fizz-bootstrap/js/common.js +++ b/fizz-bootstrap/js/common.js @@ -166,11 +166,11 @@ var common = { }, /** - * 获取步骤中调用的接口的响应头 + * 获取步骤中调用的接口的响应体 * @param {*} ctx 上下文 【必填】 * @param {*} stepName 步骤名【必填】 * @param {*} requestName 请求的接口名 【必填】 - * @param {*} field 字段名 【选填】,不传时返回整个响应头 + * @param {*} field 字段名 【选填】,不传时返回整个响应体 */ getStepRespBody: function (ctx, stepName, requestName, field){ var resp = this.getStepResp(ctx, stepName, requestName); diff --git a/fizz-bootstrap/src/main/resources/js/common.js b/fizz-bootstrap/src/main/resources/js/common.js index cccb334..c8eb437 100644 --- a/fizz-bootstrap/src/main/resources/js/common.js +++ b/fizz-bootstrap/src/main/resources/js/common.js @@ -166,11 +166,11 @@ var common = { }, /** - * 获取步骤中调用的接口的响应头 + * 获取步骤中调用的接口的响应体 * @param {*} ctx 上下文 【必填】 * @param {*} stepName 步骤名【必填】 * @param {*} requestName 请求的接口名 【必填】 - * @param {*} field 字段名 【选填】,不传时返回整个响应头 + * @param {*} field 字段名 【选填】,不传时返回整个响应体 */ getStepRespBody: function (ctx, stepName, requestName, field){ var resp = this.getStepResp(ctx, stepName, requestName); From 15036163eda395e3257cf9730b54fa16d8f4a3c8 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Mon, 10 Apr 2023 18:08:58 +0800 Subject: [PATCH 8/8] Release 2.7.2 --- README.en-us.md | 3 ++- README.md | 3 ++- docker-compose.yml | 6 +++--- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 9 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.en-us.md b/README.en-us.md index c0f2707..5c7de49 100644 --- a/README.en-us.md +++ b/README.en-us.md @@ -4,7 +4,7 @@ English | [简体中文](./README.md)

- Version + Version Documentation @@ -107,6 +107,7 @@ Starting from v1.3.0, the frontend and backend of the management backend are mer | v2.6.6 | v2.6.6 | | v2.7.0 | v2.7.0 | | v2.7.1 | v2.7.1 | +| v2.7.2 | v2.7.2 | Please download the corresponding management backend version according to the version of the community version diff --git a/README.md b/README.md index 7c34a62..539f8cc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

- Version + Version Documentation @@ -109,6 +109,7 @@ API地址:http://demo.fizzgate.com/proxy/[服务名]/[API_Path] | v2.6.6 | v2.6.6 | | v2.7.0 | v2.7.0 | | v2.7.1 | v2.7.1 | +| v2.7.2 | v2.7.2 | 请根据社区版的版本下载对应的管理后台版本 diff --git a/docker-compose.yml b/docker-compose.yml index 77d39ae..3436910 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.6" services: fizz-mysql: - image: "fizzgate/fizz-mysql:2.7.1" + image: "fizzgate/fizz-mysql:2.7.2" container_name: fizz-mysql restart: always hostname: fizz-mysql @@ -27,7 +27,7 @@ services: - fizz fizz-gateway-community: - image: "fizzgate/fizz-gateway-community:2.7.1" + image: "fizzgate/fizz-gateway-community:2.7.2" container_name: fizz-gateway-community restart: always hostname: fizz-gateway-community @@ -48,7 +48,7 @@ services: - fizz fizz-manager-professional: - image: "fizzgate/fizz-manager-professional:2.7.1" + image: "fizzgate/fizz-manager-professional:2.7.2" container_name: fizz-manager-professional restart: always hostname: fizz-manager-professional diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 9e1fb67..7e46f76 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -6,7 +6,7 @@ fizz-gateway-community com.fizzgate - 2.7.2-SNAPSHOT + 2.7.2 ../pom.xml diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index e3e6140..b109203 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.2-SNAPSHOT + 2.7.2 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 4f67eed..d35ef94 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.2-SNAPSHOT + 2.7.2 ../pom.xml 4.0.0 diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 52ec30d..c07b832 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.2-SNAPSHOT + 2.7.2 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index eecfae5..a73333b 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.7.2-SNAPSHOT + 2.7.2 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 5309cc0..c1a0cd4 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.7.2-SNAPSHOT + 2.7.2 pom fizz-common