diff --git a/fizz-common/src/main/java/we/util/Consts.java b/fizz-common/src/main/java/we/util/Consts.java index 05c5c91..2c3ed0c 100644 --- a/fizz-common/src/main/java/we/util/Consts.java +++ b/fizz-common/src/main/java/we/util/Consts.java @@ -44,7 +44,7 @@ public final class Consts { public static final char SINGLE_QUOTE = '\''; public static final char ASTERISK = '*'; public static final char DASH = '-'; - public static final char UNDERLINE = '_'; + public static final char UNDER_LINE = '_'; public static final char EQUAL = '='; public static final char AT = '@'; public static final char LEFT_SQUARE_BRACKET = '['; diff --git a/fizz-core/src/main/java/we/filter/PreprocessFilter.java b/fizz-core/src/main/java/we/filter/PreprocessFilter.java index 9c95c7b..a9aae34 100644 --- a/fizz-core/src/main/java/we/filter/PreprocessFilter.java +++ b/fizz-core/src/main/java/we/filter/PreprocessFilter.java @@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; @@ -34,9 +35,11 @@ import we.plugin.auth.AuthPluginFilter; import we.plugin.stat.StatPluginFilter; import we.proxy.Route; import we.util.ReactorUtils; +import we.util.Result; import we.util.WebUtils; import javax.annotation.Resource; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -74,45 +77,36 @@ public class PreprocessFilter extends FizzWebFilter { return process(exchange, chain, eas, vm); } - // TODO + // TODO: improve private Mono process(ServerWebExchange exchange, WebFilterChain chain, Map eas, Mono vm) { return chain(exchange, vm, authPluginFilter).defaultIfEmpty(ReactorUtils.NULL) .flatMap( v -> { - Object authRes = WebUtils.getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT); + Result authRes = (Result) WebUtils.getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT); + if (authRes.code == Result.FAIL) { + return WebUtils.responseError(exchange, HttpStatus.FORBIDDEN.value(), authRes.msg); + } Mono m = ReactorUtils.getInitiateMono(); - if (authRes instanceof ApiConfig) { - ApiConfig ac = (ApiConfig) authRes; - - Route route = ac.getRoute(exchange); - exchange.getAttributes().put(WebUtils.ROUTE, route); - - afterAuth(exchange, ac, route); - m = executeFixedPluginFilters(exchange); - m = m.defaultIfEmpty(ReactorUtils.NULL); - if (route.pluginConfigs == null || route.pluginConfigs.isEmpty()) { - return m.flatMap(func(exchange, chain)); - } else { - return m.flatMap( - nil -> { - eas.put(FizzPluginFilterChain.WEB_FILTER_CHAIN, chain); - return FizzPluginFilterChain.next(exchange); - } - ); - } - } else if (authRes == ApiConfigService.Access.YES) { + ApiConfig ac = authRes.data; + if (ac == null) { afterAuth(exchange, null, null); m = executeFixedPluginFilters(exchange); return m.defaultIfEmpty(ReactorUtils.NULL).flatMap(func(exchange, chain)); + } + Route route = ac.getRoute(exchange); + eas.put(WebUtils.ROUTE, route); + afterAuth(exchange, ac, route); + m = executeFixedPluginFilters(exchange); + m = m.defaultIfEmpty(ReactorUtils.NULL); + if (CollectionUtils.isEmpty(route.pluginConfigs)) { + return m.flatMap(func(exchange, chain)); } else { - String err = null; - if (authRes instanceof ApiConfigService.Access) { - ApiConfigService.Access access = (ApiConfigService.Access) authRes; - err = access.getReason(); - } else { - err = authRes.toString(); - } - return WebUtils.responseError(exchange, HttpStatus.FORBIDDEN.value(), err); + return m.flatMap( + nil -> { + eas.put(FizzPluginFilterChain.WEB_FILTER_CHAIN, chain); + return FizzPluginFilterChain.next(exchange); + } + ); } } ); diff --git a/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java b/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java index 62ceea3..04cf12b 100644 --- a/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java +++ b/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java @@ -44,7 +44,7 @@ public final class FizzPluginFilterChain { public static Mono next(ServerWebExchange exchange) { Iterator it = exchange.getAttribute(pluginConfigsIt); if (it == null) { - List pcs = WebUtils.getApiConfig(exchange).pluginConfigs; + List pcs = WebUtils.getRoute(exchange).pluginConfigs; it = pcs.iterator(); Map attris = exchange.getAttributes(); attris.put(pluginConfigsIt, it); diff --git a/fizz-core/src/main/java/we/plugin/PluginConfig.java b/fizz-core/src/main/java/we/plugin/PluginConfig.java index 7a7dfea..7340733 100644 --- a/fizz-core/src/main/java/we/plugin/PluginConfig.java +++ b/fizz-core/src/main/java/we/plugin/PluginConfig.java @@ -30,13 +30,13 @@ import java.util.Map; public class PluginConfig { - public static final String CUSTOM_CONFIG = "$fc"; + public static final String CUSTOM_CONFIG = "fcK"; public String plugin; // tb_plugin.eng_name public String fixedConfig; - public Map config = Collections.EMPTY_MAP; + public Map config = Collections.emptyMap(); // @JsonProperty(value = "config", access = JsonProperty.Access.WRITE_ONLY) public void setConfig(String confJson) { diff --git a/fizz-core/src/main/java/we/plugin/auth/AbstractCustomAuth.java b/fizz-core/src/main/java/we/plugin/auth/AbstractCustomAuth.java new file mode 100644 index 0000000..8b15d15 --- /dev/null +++ b/fizz-core/src/main/java/we/plugin/auth/AbstractCustomAuth.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.plugin.auth; + +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; +import we.util.Result; +import we.util.Utils; + +/** + * @author hongqiaowei + */ + +public abstract class AbstractCustomAuth implements CustomAuth { + + /** + * @deprecated + */ + @Override + public Mono auth(ServerWebExchange exchange, String appId, String ip, String timestamp, String sign, App fizzAppConfig) { + throw Utils.runtimeExceptionWithoutStack("don't implement me!"); + } + + /** + * @return if authentication pass then Result.code = Result.SUCC, otherwise Result.code = Result.FAIL + */ + public abstract Mono> auth(String appId, String ip, String timestamp, String sign, App fizzAppConfig, ServerWebExchange exchange); +} diff --git a/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java b/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java index 53cc0d6..4a4e2b0 100644 --- a/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java +++ b/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java @@ -54,7 +54,7 @@ public class ApiConfig { public static final char ALLOW = 'a'; - public static final char FORBID = 'f'; +// public static final char FORBID = 'f'; public static final String ALL_METHOD = "AM"; @@ -62,25 +62,36 @@ public class ApiConfig { private static final int ENABLE = 1; - private static final int UNABLE = 0; +// private static final int UNABLE = 0; + @JsonProperty( + access = JsonProperty.Access.WRITE_ONLY + ) public int id; // tb_api_auth.id + @JsonProperty( + access = JsonProperty.Access.WRITE_ONLY + ) public int isDeleted = 0; // tb_api_auth.is_deleted public Set gatewayGroups = Stream.of(GatewayGroup.DEFAULT).collect(Collectors.toSet()); - public String service; // a + public String service; public String backendService; - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + @JsonProperty( + access = JsonProperty.Access.WRITE_ONLY + ) public HttpMethod method; public Object fizzMethod = ALL_METHOD; public String path = match_all; + @JsonProperty( + access = JsonProperty.Access.WRITE_ONLY + ) public boolean exactMatch = false; public String backendPath; @@ -180,7 +191,7 @@ public class ApiConfig { i = Math.abs(i); } return httpHostPorts.get( - i % httpHostPorts.size() + i % httpHostPorts.size() ); } @@ -207,17 +218,17 @@ public class ApiConfig { public Route getRoute(ServerWebExchange exchange) { ServerHttpRequest request = exchange.getRequest(); - Route r = new Route().type(this.type) - .method(request.getMethod()) + Route r = new Route().type( this.type) + .method( request.getMethod()) .backendService(this.backendService) - .backendPath(this.backendPath) - .query(WebUtils.getClientReqQuery(exchange)) - .pluginConfigs(this.pluginConfigs) - .rpcMethod(this.rpcMethod) - .rpcParamTypes(this.rpcParamTypes) - .rpcGroup(this.rpcGroup) - .rpcVersion(this.rpcVersion) - .timeout(this.timeout); + .backendPath( this.backendPath) + .query( WebUtils.getClientReqQuery(exchange)) + .pluginConfigs( this.pluginConfigs) + .rpcMethod( this.rpcMethod) + .rpcParamTypes( this.rpcParamTypes) + .rpcGroup( this.rpcGroup) + .rpcVersion( this.rpcVersion) + .timeout( this.timeout); if (this.type == Type.REVERSE_PROXY) { r = r.nextHttpHostPort(getNextHttpHostPort()); diff --git a/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java b/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java index 767a3c0..bd2ac2d 100644 --- a/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java +++ b/fizz-core/src/main/java/we/plugin/auth/ApiConfigService.java @@ -25,7 +25,9 @@ import org.springframework.data.redis.core.ReactiveStringRedisTemplate; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -41,6 +43,7 @@ import javax.annotation.Resource; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.regex.Pattern; /** * @author hongqiaowei @@ -51,11 +54,7 @@ public class ApiConfigService { private static final Logger log = LoggerFactory.getLogger(ApiConfigService.class); - private static final String mpps = "$mpps"; - - private static final String deny = "route which match current request can't be access by client app, or is not exposed to current gateway group"; - - public static final String AUTH_MSG = "$authMsg"; + private static final String macs = "macsT"; public Map serviceConfigMap = new HashMap<>(128); @@ -112,11 +111,13 @@ public class ApiConfigService { ); } + // TODO: no need like this public void refreshLocalCache() throws Throwable { this.init(null); initPlugin(); } + // TODO: no need like this private void init(Supplier> doAfterLoadCache) throws Throwable { Map apiConfigMapTmp = new HashMap<>(128); Map serviceConfigMapTmp = new HashMap<>(128); @@ -129,7 +130,7 @@ public class ApiConfigService { return Flux.just(e); } Object v = e.getValue(); - log.info("api config: " + v.toString(), LogService.BIZ_ID, k.toString()); + log.info("get api config data: {}", v.toString(), LogService.BIZ_ID, k.toString()); String json = (String) v; try { ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class); @@ -138,7 +139,7 @@ public class ApiConfigService { return Flux.just(e); } catch (Throwable t) { throwable[0] = t; - log.info(json, t); + log.error("deser {}", json, t); return Flux.error(t); } }).blockLast())).flatMap( @@ -146,7 +147,6 @@ public class ApiConfigService { if (throwable[0] != null) { return Mono.error(throwable[0]); } - if (doAfterLoadCache != null) { return doAfterLoadCache.get(); } else { @@ -157,26 +157,27 @@ public class ApiConfigService { if (error != ReactorUtils.EMPTY_THROWABLE) { throw error; } - this.apiConfigMap = apiConfigMapTmp; this.serviceConfigMap = serviceConfigMapTmp; } + // TODO: no need like this private Mono lsnApiConfigChange() { final Throwable[] throwable = new Throwable[1]; final boolean[] b = {false}; - rt.listenToChannel(apiConfigServiceProperties.getFizzApiConfigChannel()).doOnError(t -> { + String ch = apiConfigServiceProperties.getFizzApiConfigChannel(); + rt.listenToChannel(ch).doOnError(t -> { throwable[0] = t; b[0] = false; - log.error("lsn " + apiConfigServiceProperties.getFizzApiConfigChannel(), t); + log.error("lsn {}", ch, t); }).doOnSubscribe( - s -> { - b[0] = true; - log.info("success to lsn on " + apiConfigServiceProperties.getFizzApiConfigChannel()); - } + s -> { + b[0] = true; + log.info("success to lsn on {}", ch); + } ).doOnNext(msg -> { String json = msg.getMessage(); - log.info(json, LogService.BIZ_ID, "acc" + System.currentTimeMillis()); + log.info("api config change: {}", json, LogService.BIZ_ID, "acc" + System.currentTimeMillis()); try { ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class); ApiConfig r = apiConfigMap.remove(ac.id); @@ -191,7 +192,7 @@ public class ApiConfigService { apiConifg2appsService.remove(ac.id); } } catch (Throwable t) { - log.info(json, t); + log.error("deser {}", json, t); } }).subscribe(); Throwable t = throwable[0]; @@ -295,14 +296,11 @@ public class ApiConfigService { private void updateServiceConfigMap(ApiConfig ac, Map serviceConfigMap) { ServiceConfig sc = serviceConfigMap.get(ac.service); if (ac.isDeleted == ApiConfig.DELETED) { - if (sc == null) { - log.info("no " + ac.service + " config to delete"); - } else { + if (sc != null) { sc.remove(ac); - if (sc.path2methodToApiConfigMapMap.isEmpty()) { + if (sc.apiConfigMap.isEmpty()) { serviceConfigMap.remove(ac.service); } - // apiConifg2appsService.remove(ac.id); } } else { if (sc == null) { @@ -315,6 +313,9 @@ public class ApiConfigService { } } + /** + * @deprecated + */ public enum Access { YES (null), @@ -344,151 +345,164 @@ public class ApiConfigService { } } - public ApiConfig getApiConfig(String app, String service, HttpMethod method, String path) { - ApiConfig ac = null; - for (String g : gatewayGroupService.currentGatewayGroupSet) { - ac = getApiConfig(service, method, path, g, app); - if (ac != null) { - return ac; - } - } - return ac; + public Result getApiConfig(String app, String service, HttpMethod method, String path) { + return getApiConfig(null, app, service, method, path); } - public ApiConfig getApiConfig(String service, HttpMethod method, String path, String gatewayGroup, String app) { + public Result getApiConfig(Set gatewayGroups, String app, String service, HttpMethod method, String path) { ServiceConfig sc = serviceConfigMap.get(service); - if (sc != null) { - List apiConfigs = sc.getApiConfigs(method, path, gatewayGroup); - if (!apiConfigs.isEmpty()) { - List matchPathPatterns = ThreadContext.getArrayList(mpps); - for (int i = 0; i < apiConfigs.size(); i++) { - ApiConfig ac = apiConfigs.get(i); - if (ac.checkApp) { - if (apiConifg2appsService.contains(ac.id, app)) { - matchPathPatterns.add(ac.path); - } - } else { - matchPathPatterns.add(ac.path); - } + if (sc == null) { + return Result.fail("no " + service + " config"); + } + if (CollectionUtils.isEmpty(gatewayGroups)) { + gatewayGroups = gatewayGroupService.currentGatewayGroupSet; + } + List apiConfigs = sc.getApiConfigs(gatewayGroups, method, path); + if (apiConfigs.isEmpty()) { + return Result.fail(service + " don't have api config matching " + gatewayGroups + " group " + method + " method " + path + " path"); + } + List appCanAccess = ThreadContext.getArrayList(macs); + for (int i = 0; i < apiConfigs.size(); i++) { + ApiConfig ac = apiConfigs.get(i); + if (ac.checkApp) { + if (StringUtils.isNotBlank(app) && apiConifg2appsService.contains(ac.id, app)) { + appCanAccess.add(ac); } - if (matchPathPatterns.isEmpty()) { - if (app == null) { - ThreadContext.set(ApiConfigService.AUTH_MSG, "no app msg in req"); - } else { - ThreadContext.set(ApiConfigService.AUTH_MSG, app + " not in app whitelist of routes which match " + gatewayGroup + ' ' + service + ' ' + method + ' ' + path); - } - } - if (!matchPathPatterns.isEmpty()) { - if (matchPathPatterns.size() > 1) { - Collections.sort(matchPathPatterns, UrlTransformUtils.ANT_PATH_MATCHER.getPatternComparator(path)); - } - String bestPathPattern = matchPathPatterns.get(0); - for (int i = 0; i < apiConfigs.size(); i++) { - ApiConfig ac = apiConfigs.get(i); - if (StringUtils.equals(ac.path, bestPathPattern)) { - return ac; + } else { + appCanAccess.add(ac); + } + } + if (appCanAccess.isEmpty()) { + return Result.fail("app " + app + " can't access " + JacksonUtils.writeValueAsString(apiConfigs)); + } + ApiConfig bestOne = appCanAccess.get(0); + if (appCanAccess.size() != 1) { + appCanAccess.sort(new ApiConfigPathPatternComparator(path)); + ApiConfig ac0 = appCanAccess.get(0); + bestOne = ac0; + ApiConfig ac1 = appCanAccess.get(1); + if (ac0.path.equals(ac1.path)) { + if (ac0.fizzMethod == ac1.fizzMethod) { + if (StringUtils.isNotBlank(app)) { + if (!ac0.checkApp) { + bestOne = ac1; } } + } else { + if (ac0.fizzMethod == ApiConfig.ALL_METHOD) { + bestOne = ac1; + } } } - } else { - ThreadContext.set(ApiConfigService.AUTH_MSG, "no " + service + " service config"); } - return null; + return Result.succ(bestOne); } - public Mono canAccess(ServerWebExchange exchange) { + public Mono> auth(ServerWebExchange exchange) { ServerHttpRequest req = exchange.getRequest(); HttpHeaders hdrs = req.getHeaders(); LogService.setBizId(WebUtils.getTraceId(exchange)); - return canAccess(exchange, WebUtils.getAppId(exchange), WebUtils.getOriginIp(exchange), getTimestamp(hdrs), getSign(hdrs), - WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange)); + return auth(exchange, WebUtils.getAppId(exchange), WebUtils.getOriginIp(exchange), getTimestamp(hdrs), getSign(hdrs), + WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange)); } - // TODO: improve ... - private Mono canAccess(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String service, HttpMethod method, String path) { + private Mono> auth(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String service, HttpMethod method, String path) { if (!systemConfig.isAggregateTestAuth()) { if (SystemConfig.DEFAULT_GATEWAY_TEST_PREFIX0.equals(WebUtils.getClientReqPathPrefix(exchange))) { - return Mono.just(Access.YES); + return Mono.just(Result.succ()); } } - ApiConfig ac = getApiConfig(app, service, method, path); - if (ac == null) { - String authMsg = (String) ThreadContext.remove(AUTH_MSG); - if (authMsg == null) { - authMsg = deny; - } - if (!apiConfigServiceProperties.isNeedAuth()) { - return Mono.just(Access.YES); + Result r = getApiConfig(app, service, method, path); + if (r.code == Result.FAIL) { + if (apiConfigServiceProperties.isNeedAuth()) { + return Mono.just(r); } else { - return logAndResult(authMsg); + return Mono.just(Result.succ()); } + } - } else if (ac.checkApp) { - App a = appService.getApp(app); - if (a.useWhiteList && !a.allow(ip)) { - return logAndResult(ip + " not in " + app + " white list", Access.IP_NOT_IN_WHITE_LIST); - } else if (a.useAuth) { - if (a.authType == App.AUTH_TYPE.SIGN) { - return authSign(ac, a, timestamp, sign); - } else if (a.authType == App.AUTH_TYPE.SECRETKEY) { - return authSecretkey(ac, a, sign); - } else if (customAuth == null) { - return logAndResult(app + " no custom auth", Access.NO_CUSTOM_AUTH); - } else { - return customAuth.auth(exchange, app, ip, timestamp, sign, a).flatMap(v -> { - if (v == Access.YES) { - return Mono.just(ac); - } else { - return Mono.just(Access.CUSTOM_AUTH_REJECT); - } - }); + ApiConfig ac = r.data; + if (ac.checkApp) { + App a = appService.getApp(app); + if (a.useWhiteList && !a.allow(ip)) { + r.code = Result.FAIL; + r.msg = ip + " not in " + app + " app white list"; + return Mono.just(r); + } + if (a.useAuth) { + if (a.authType == App.AUTH_TYPE.SIGN) { + return authSign(a, timestamp, sign, r); + } else if (a.authType == App.AUTH_TYPE.SECRET_KEY) { + return authSecretKey(a, sign, r); + } else if (customAuth == null) { + r.code = Result.FAIL; + r.msg = "no custom auth bean for " + app; + return Mono.just(r); + } else { + if (customAuth instanceof AbstractCustomAuth) { + AbstractCustomAuth abstractCustomAuth = (AbstractCustomAuth) customAuth; + return abstractCustomAuth.auth(app, ip, timestamp, sign, a, exchange) + .flatMap( + res -> { + if (res.code == Result.FAIL) { + r.code = res.code; + r.msg = res.msg; + } + return Mono.just(r); + } + ); + } else { + return customAuth.auth(exchange, app, ip, timestamp, sign, a) + .flatMap( + v -> { + if (v == Access.YES) { + return Mono.just(r); + } else { + r.code = Result.FAIL; + r.msg = v.getReason(); + return Mono.just(r); + } + } + ); + } + } } - } else { - return Mono.just(ac); - } - - } else { - return Mono.just(ac); } + return Mono.just(r); } - private Mono authSign(ApiConfig ac, App a, String timestamp, String sign) { + private Mono> authSign(App a, String timestamp, String sign, Result r) { if (StringUtils.isAnyBlank(timestamp, sign)) { - return logAndResult(a.app + " lack timestamp " + timestamp + " or sign " + sign, Access.NO_TIMESTAMP_OR_SIGN); + r.code = Result.FAIL; + r.msg = a.app + " not present timestamp " + timestamp + " or sign " + sign; } else if (validate(a.app, timestamp, a.secretkey, sign)) { - return Mono.just(ac); } else { - return logAndResult(a.app + " sign " + sign + " invalid", Access.SIGN_INVALID); + r.code = Result.FAIL; + r.msg = a.app + " sign " + sign + " invalid"; } + return Mono.just(r); } private boolean validate(String app, String timestamp, String secretKey, String sign) { StringBuilder b = ThreadContext.getStringBuilder(); - b.append(app).append(Consts.S.UNDERLINE).append(timestamp).append(Consts.S.UNDERLINE).append(secretKey); + b.append(app) .append(Consts.S.UNDER_LINE) + .append(timestamp).append(Consts.S.UNDER_LINE) + .append(secretKey); return sign.equalsIgnoreCase(DigestUtils.md532(b.toString())); } - private Mono authSecretkey(ApiConfig ac, App a, String sign) { + private Mono> authSecretKey(App a, String sign, Result r) { if (StringUtils.isBlank(sign)) { - return logAndResult(a.app + " lack secretkey " + sign, Access.NO_SECRETKEY); + r.code = Result.FAIL; + r.msg = a.app + " not present secret key " + sign; } else if (a.secretkey.equals(sign)) { - return Mono.just(ac); } else { - return logAndResult(a.app + " secretkey " + sign + " invalid", Access.SECRETKEY_INVALID); + r.code = Result.FAIL; + r.msg = a.app + " secret key " + sign + " invalid"; } - } - - private Mono logAndResult(String msg, Access access) { - log.warn(msg); - return Mono.just(access); - } - - private Mono logAndResult(String msg) { - log.warn(msg); - return Mono.just(msg); + return Mono.just(r); } private String getTimestamp(HttpHeaders reqHdrs) { @@ -512,4 +526,169 @@ public class ApiConfigService { } return null; } + + private static class ApiConfigPathPatternComparator implements Comparator { + + private final String path; + + public ApiConfigPathPatternComparator(String path) { + this.path = path; + } + + @Override + public int compare(ApiConfig ac1, ApiConfig ac2) { + String pattern1 = ac1.path, pattern2 = ac2.path; + ApiConfigPathPatternComparator.PatternInfo info1 = new ApiConfigPathPatternComparator.PatternInfo(pattern1); + ApiConfigPathPatternComparator.PatternInfo info2 = new ApiConfigPathPatternComparator.PatternInfo(pattern2); + + if (info1.isLeastSpecific() && info2.isLeastSpecific()) { + return 0; + } + else if (info1.isLeastSpecific()) { + return 1; + } + else if (info2.isLeastSpecific()) { + return -1; + } + + boolean pattern1EqualsPath = pattern1.equals(this.path); + boolean pattern2EqualsPath = pattern2.equals(this.path); + if (pattern1EqualsPath && pattern2EqualsPath) { + return 0; + } + else if (pattern1EqualsPath) { + return -1; + } + else if (pattern2EqualsPath) { + return 1; + } + + if (info1.isPrefixPattern() && info2.isPrefixPattern()) { + return info2.getLength() - info1.getLength(); + } + else if (info1.isPrefixPattern() && info2.getDoubleWildcards() == 0) { + return 1; + } + else if (info2.isPrefixPattern() && info1.getDoubleWildcards() == 0) { + return -1; + } + + if (info1.getTotalCount() != info2.getTotalCount()) { + return info1.getTotalCount() - info2.getTotalCount(); + } + + if (info1.getLength() != info2.getLength()) { + return info2.getLength() - info1.getLength(); + } + + if (info1.getSingleWildcards() < info2.getSingleWildcards()) { + return -1; + } + else if (info2.getSingleWildcards() < info1.getSingleWildcards()) { + return 1; + } + + if (info1.getUriVars() < info2.getUriVars()) { + return -1; + } + else if (info2.getUriVars() < info1.getUriVars()) { + return 1; + } + + return 0; + } + + private static class PatternInfo { + + private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{[^/]+?}"); + + @Nullable + private final String pattern; + + private int uriVars; + + private int singleWildcards; + + private int doubleWildcards; + + private boolean catchAllPattern; + + private boolean prefixPattern; + + @Nullable + private Integer length; + + public PatternInfo(@Nullable String pattern) { + this.pattern = pattern; + if (this.pattern != null) { + initCounters(); + this.catchAllPattern = this.pattern.equals("/**"); + this.prefixPattern = !this.catchAllPattern && this.pattern.endsWith("/**"); + } + if (this.uriVars == 0) { + this.length = (this.pattern != null ? this.pattern.length() : 0); + } + } + + protected void initCounters() { + int pos = 0; + if (this.pattern != null) { + while (pos < this.pattern.length()) { + if (this.pattern.charAt(pos) == '{') { + this.uriVars++; + pos++; + } + else if (this.pattern.charAt(pos) == '*') { + if (pos + 1 < this.pattern.length() && this.pattern.charAt(pos + 1) == '*') { + this.doubleWildcards++; + pos += 2; + } + else if (pos > 0 && !this.pattern.substring(pos - 1).equals(".*")) { + this.singleWildcards++; + pos++; + } + else { + pos++; + } + } + else { + pos++; + } + } + } + } + + public int getUriVars() { + return this.uriVars; + } + + public int getSingleWildcards() { + return this.singleWildcards; + } + + public int getDoubleWildcards() { + return this.doubleWildcards; + } + + public boolean isLeastSpecific() { + return (this.pattern == null || this.catchAllPattern); + } + + public boolean isPrefixPattern() { + return this.prefixPattern; + } + + public int getTotalCount() { + return this.uriVars + this.singleWildcards + (2 * this.doubleWildcards); + } + + public int getLength() { + if (this.length == null) { + this.length = (this.pattern != null ? + VARIABLE_PATTERN.matcher(this.pattern).replaceAll("#").length() : 0); + } + return this.length; + } + } + } } diff --git a/fizz-core/src/main/java/we/plugin/auth/App.java b/fizz-core/src/main/java/we/plugin/auth/App.java index c7eb00f..979121f 100644 --- a/fizz-core/src/main/java/we/plugin/auth/App.java +++ b/fizz-core/src/main/java/we/plugin/auth/App.java @@ -35,9 +35,9 @@ public class App { public static final int DELETED = 1; static interface AUTH_TYPE { - static final int SIGN = 1; - static final int CUSTOM = 2; - static final int SECRETKEY = 3; + static final int SIGN = 1; + static final int CUSTOM = 2; + static final int SECRET_KEY = 3; } public int isDeleted = 0; // tb_app_auth.is_deleted @@ -61,7 +61,7 @@ public class App { public Map> ips = new HashMap<>(); public void setUseAuth(int i) { - if (i == AUTH_TYPE.SIGN || i == AUTH_TYPE.SECRETKEY || i == AUTH_TYPE.CUSTOM) { + if (i == AUTH_TYPE.SIGN || i == AUTH_TYPE.SECRET_KEY || i == AUTH_TYPE.CUSTOM) { useAuth = true; } } diff --git a/fizz-core/src/main/java/we/plugin/auth/AuthPluginFilter.java b/fizz-core/src/main/java/we/plugin/auth/AuthPluginFilter.java index fa18102..f3389ad 100644 --- a/fizz-core/src/main/java/we/plugin/auth/AuthPluginFilter.java +++ b/fizz-core/src/main/java/we/plugin/auth/AuthPluginFilter.java @@ -32,6 +32,7 @@ import java.util.Map; /** * @author hongqiaowei + * @apiNote unstable. */ @Component(AuthPluginFilter.AUTH_PLUGIN_FILTER) @@ -39,19 +40,19 @@ public class AuthPluginFilter extends PluginFilter { private static final Logger log = LoggerFactory.getLogger(AuthPluginFilter.class); - public static final String AUTH_PLUGIN_FILTER = "authPlugin"; + public static final String AUTH_PLUGIN_FILTER = "authPlugin"; - public static final String RESULT = "result"; + public static final String RESULT = "result"; @Resource private ApiConfigService apiConfigService; @Override - public Mono doFilter(ServerWebExchange exchange, Map config, String fixedConfig) { - return apiConfigService.canAccess(exchange).flatMap( + public Mono doFilter(ServerWebExchange exchange, Map config, String pluginConfig) { + return apiConfigService.auth(exchange).flatMap( r -> { if (log.isDebugEnabled()) { - log.debug("req auth: " + r, LogService.BIZ_ID, WebUtils.getTraceId(exchange)); + log.debug("req auth: {}", r, LogService.BIZ_ID, WebUtils.getTraceId(exchange)); } Map data = Collections.singletonMap(RESULT, r); return WebUtils.transmitSuccessFilterResultAndEmptyMono(exchange, AUTH_PLUGIN_FILTER, data); diff --git a/fizz-core/src/main/java/we/plugin/auth/CustomAuth.java b/fizz-core/src/main/java/we/plugin/auth/CustomAuth.java index 0a8f5ab..5c3e16b 100644 --- a/fizz-core/src/main/java/we/plugin/auth/CustomAuth.java +++ b/fizz-core/src/main/java/we/plugin/auth/CustomAuth.java @@ -21,6 +21,8 @@ import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** + * extend AbstractCustomAuth instead implement this class. + * * @author hongqiaowei */ @@ -28,6 +30,8 @@ public interface CustomAuth { /** * 认证通过返回 Mono, 不通过返回 Mono + * + * @deprecated */ Mono auth(ServerWebExchange exchange, String appId, String ip, String timestamp, String sign, App fizzAppConfig); } diff --git a/fizz-core/src/main/java/we/plugin/auth/GatewayGroup2apiConfig.java b/fizz-core/src/main/java/we/plugin/auth/GatewayGroup2apiConfig.java index 250cef2..f2695f9 100644 --- a/fizz-core/src/main/java/we/plugin/auth/GatewayGroup2apiConfig.java +++ b/fizz-core/src/main/java/we/plugin/auth/GatewayGroup2apiConfig.java @@ -31,6 +31,7 @@ import java.util.Set; * @author hongqiaowei */ +@Deprecated public class GatewayGroup2apiConfig { private Map> configMap = new HashMap<>(8); diff --git a/fizz-core/src/main/java/we/plugin/auth/ServiceConfig.java b/fizz-core/src/main/java/we/plugin/auth/ServiceConfig.java index 945587b..0ba7d67 100644 --- a/fizz-core/src/main/java/we/plugin/auth/ServiceConfig.java +++ b/fizz-core/src/main/java/we/plugin/auth/ServiceConfig.java @@ -32,134 +32,125 @@ import java.util.*; public class ServiceConfig { - private static final Logger log = LoggerFactory.getLogger(ServiceConfig.class); + private static final Logger log = LoggerFactory.getLogger(ServiceConfig.class); - private static final String gg2acs = "$gg2acs"; + private static final String gmpT = "gmpT"; - private static final String acs = "$acs"; + private static final String gsmpT = "gsmpT"; - public String id; + private String id; - @JsonIgnore - public Map apiConfigMap = new HashMap<>(); - - public Map> path2methodToApiConfigMapMap = new HashMap<>(); + public Map + > + > + apiConfigMap = new HashMap<>(); public ServiceConfig(String id) { this.id = id; } public void add(ApiConfig ac) { - apiConfigMap.put(ac.id, ac); - Map method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path); - if (method2apiConfigMap == null) { - method2apiConfigMap = new HashMap(); - GatewayGroup2apiConfig gatewayGroup2apiConfig = new GatewayGroup2apiConfig(); - gatewayGroup2apiConfig.add(ac); - method2apiConfigMap.put(ac.fizzMethod, gatewayGroup2apiConfig); - path2methodToApiConfigMapMap.put(ac.path, method2apiConfigMap); - } else { - GatewayGroup2apiConfig gatewayGroup2apiConfig = method2apiConfigMap.get(ac.fizzMethod); - if (gatewayGroup2apiConfig == null) { - gatewayGroup2apiConfig = new GatewayGroup2apiConfig(); - method2apiConfigMap.put(ac.fizzMethod, gatewayGroup2apiConfig); + for (String gatewayGroup : ac.gatewayGroups) { + Map> method2pathPattenMap = apiConfigMap.get(gatewayGroup); + if (method2pathPattenMap == null) { + method2pathPattenMap = new HashMap<>(); + apiConfigMap.put(gatewayGroup, method2pathPattenMap); } - gatewayGroup2apiConfig.add(ac); + Map pathPattern2apiConfigMap = method2pathPattenMap.get(ac.fizzMethod); + if (pathPattern2apiConfigMap == null) { + pathPattern2apiConfigMap = new HashMap<>(); + method2pathPattenMap.put(ac.fizzMethod, pathPattern2apiConfigMap); + } + pathPattern2apiConfigMap.put(ac.path, ac); } - log.info("add " + ac); + log.info("{} service add api config: {}", id, ac); } public void remove(ApiConfig ac) { - ApiConfig remove = apiConfigMap.remove(ac.id); - Map method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path); - if (method2apiConfigMap == null) { - log.info("no config to delete for " + ac.service + ' ' + ac.path); - } else { - GatewayGroup2apiConfig gatewayGroup2apiConfig = method2apiConfigMap.get(ac.fizzMethod); - if (gatewayGroup2apiConfig == null) { - log.info("no config to delete for " + ac.service + ' ' + ac.fizzMethod + ' ' + ac.path); - } else { - log.info(id + " remove " + ac); - gatewayGroup2apiConfig.remove(ac); - if (gatewayGroup2apiConfig.getConfigMap().isEmpty()) { - method2apiConfigMap.remove(ac.fizzMethod); - if (method2apiConfigMap.isEmpty()) { - path2methodToApiConfigMapMap.remove(ac.path); + for (String gatewayGroup : ac.gatewayGroups) { + Map> method2pathPattenMap = apiConfigMap.get(gatewayGroup); + if (method2pathPattenMap != null) { + Map pathPattern2apiConfigMap = method2pathPattenMap.get(ac.fizzMethod); + if (pathPattern2apiConfigMap != null) { + pathPattern2apiConfigMap.remove(ac.path); + + if (pathPattern2apiConfigMap.isEmpty()) { + method2pathPattenMap.remove(ac.fizzMethod); + if (method2pathPattenMap.isEmpty()) { + apiConfigMap.remove(gatewayGroup); + } } } } } + log.info("{} service remove api config: {}", id, ac); } public void update(ApiConfig ac) { - ApiConfig prev = apiConfigMap.put(ac.id, ac); - log.info(prev + " is updated by " + ac + " in api config map"); - Map method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path); - if (method2apiConfigMap == null) { - method2apiConfigMap = new HashMap(); - GatewayGroup2apiConfig gatewayGroup2apiConfig = new GatewayGroup2apiConfig(); - gatewayGroup2apiConfig.add(ac); - method2apiConfigMap.put(ac.fizzMethod, gatewayGroup2apiConfig); - path2methodToApiConfigMapMap.put(ac.path, method2apiConfigMap); - } else { - GatewayGroup2apiConfig gatewayGroup2apiConfig = method2apiConfigMap.get(ac.fizzMethod); - if (gatewayGroup2apiConfig == null) { - gatewayGroup2apiConfig = new GatewayGroup2apiConfig(); - method2apiConfigMap.put(ac.fizzMethod, gatewayGroup2apiConfig); - gatewayGroup2apiConfig.add(ac); - } else { - log.info(id + " update " + ac); - gatewayGroup2apiConfig.update(ac); + ApiConfig prevApiConfig = null; + for (String gatewayGroup : ac.gatewayGroups) { + Map> method2pathPattenMap = apiConfigMap.get(gatewayGroup); + if (method2pathPattenMap == null) { + method2pathPattenMap = new HashMap<>(); + apiConfigMap.put(gatewayGroup, method2pathPattenMap); } + Map pathPattern2apiConfigMap = method2pathPattenMap.get(ac.fizzMethod); + if (pathPattern2apiConfigMap == null) { + pathPattern2apiConfigMap = new HashMap<>(); + method2pathPattenMap.put(ac.fizzMethod, pathPattern2apiConfigMap); + } + prevApiConfig = pathPattern2apiConfigMap.put(ac.path, ac); } + log.info("{} service update api config {} with {}", id, prevApiConfig, ac); } @JsonIgnore - public List getApiConfigs(HttpMethod method, String path, String gatewayGroup) { - - List matchGatewayGroup2apiConfigs = ThreadContext.getArrayList(gg2acs); - - Set>> es = path2methodToApiConfigMapMap.entrySet(); - for (Map.Entry> e : es) { - Map method2gatewayGroupToApiConfigMap = e.getValue(); - GatewayGroup2apiConfig gatewayGroup2apiConfig = method2gatewayGroupToApiConfigMap.get(method); - if (gatewayGroup2apiConfig == null) { - gatewayGroup2apiConfig = method2gatewayGroupToApiConfigMap.get(ApiConfig.ALL_METHOD); - } - if (gatewayGroup2apiConfig != null) { - String pathPattern = e.getKey(); - if (ApiConfig.isAntPathPattern(pathPattern)) { - if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) { - matchGatewayGroup2apiConfigs.add(gatewayGroup2apiConfig); - } - } else if (path.equals(pathPattern)) { - matchGatewayGroup2apiConfigs.add(gatewayGroup2apiConfig); - } - } + public List getApiConfigs(Set gatewayGroups, HttpMethod method, String path) { + ArrayList result = ThreadContext.getArrayList(gsmpT); + for (String gatewayGroup : gatewayGroups) { + List apiConfigs = getApiConfigs(gatewayGroup, method, path); + result.addAll(apiConfigs); } + return result; + } - if (matchGatewayGroup2apiConfigs.isEmpty()) { - ThreadContext.set(ApiConfigService.AUTH_MSG, id + " no route match " + method + ' ' + path); + @JsonIgnore + public List getApiConfigs(String gatewayGroup, HttpMethod method, String path) { + Map> method2pathPattenMap = apiConfigMap.get(gatewayGroup); + if (method2pathPattenMap == null) { return Collections.emptyList(); } else { - List lst = ThreadContext.getArrayList(acs); - for (int i = 0; i < matchGatewayGroup2apiConfigs.size(); i++) { - GatewayGroup2apiConfig gatewayGroup2apiConfig = matchGatewayGroup2apiConfigs.get(i); - Set apiConfigs = gatewayGroup2apiConfig.get(gatewayGroup); - if (apiConfigs == null) { - ThreadContext.set(ApiConfigService.AUTH_MSG, "route which match " + id + ' ' + method + ' ' + path + " is not exposed to " + gatewayGroup); - } else { - for (ApiConfig ac : apiConfigs) { - if (ac.access == ApiConfig.ALLOW) { - lst.add(ac); - } + ArrayList result = ThreadContext.getArrayList(gmpT); + Map pathPattern2apiConfigMap = method2pathPattenMap.get(method); + if (pathPattern2apiConfigMap != null) { + checkPathPattern(pathPattern2apiConfigMap, path, result); + } + pathPattern2apiConfigMap = method2pathPattenMap.get(ApiConfig.ALL_METHOD); + if (pathPattern2apiConfigMap != null) { + checkPathPattern(pathPattern2apiConfigMap, path, result); + } + return result; + } + } + + private void checkPathPattern(Map pathPattern2apiConfigMap, String path, ArrayList result) { + Set> entries = pathPattern2apiConfigMap.entrySet(); + for (Map.Entry entry : entries) { + String pathPattern = entry.getKey(); + ApiConfig apiConfig = entry.getValue(); + if (apiConfig.access == ApiConfig.ALLOW) { + if (apiConfig.exactMatch) { + if (pathPattern.equals(path)) { + result.add(apiConfig); } - if (lst.isEmpty()) { - ThreadContext.set(ApiConfigService.AUTH_MSG, "route which match " + id + ' ' + method + ' ' + path + " not allow access"); + } else { + if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) { + result.add(apiConfig); } } } - return lst; } } } diff --git a/fizz-core/src/main/java/we/plugin/stat/StatPluginFilter.java b/fizz-core/src/main/java/we/plugin/stat/StatPluginFilter.java index dbbdcfb..893fe49 100644 --- a/fizz-core/src/main/java/we/plugin/stat/StatPluginFilter.java +++ b/fizz-core/src/main/java/we/plugin/stat/StatPluginFilter.java @@ -24,21 +24,20 @@ import org.springframework.data.redis.core.ReactiveStringRedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; -import we.flume.clients.log4j2appender.LogService; import we.config.AggregateRedisConfig; +import we.flume.clients.log4j2appender.LogService; import we.plugin.PluginFilter; import we.plugin.auth.GatewayGroupService; import we.util.Consts; import we.util.ThreadContext; import we.util.WebUtils; -import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.Iterator; import java.util.Map; /** * @author hongqiaowei + * @apiNote unstable. */ @Component(StatPluginFilter.STAT_PLUGIN_FILTER) @@ -46,21 +45,21 @@ public class StatPluginFilter extends PluginFilter { private static final Logger log = LoggerFactory.getLogger(StatPluginFilter.class); - public static final String STAT_PLUGIN_FILTER = "statPlugin"; + public static final String STAT_PLUGIN_FILTER = "statPlugin"; - private static final String ip = "\"ip\":"; + private static final String ip = "\"ip\":"; - private static final String gatewayGroup = "\"gatewayGroup\":"; + private static final String gatewayGroup = "\"gatewayGroup\":"; - private static final String service = "\"service\":"; + private static final String service = "\"service\":"; - private static final String appid = "\"appid\":"; + private static final String appid = "\"appid\":"; - private static final String apiMethod = "\"apiMethod\":"; + private static final String apiMethod = "\"apiMethod\":"; - private static final String apiPath = "\"apiPath\":"; + private static final String apiPath = "\"apiPath\":"; - private static final String reqTime = "\"reqTime\":"; + private static final String reqTime = "\"reqTime\":"; @Resource private StatPluginFilterProperties statPluginFilterProperties; @@ -71,40 +70,36 @@ public class StatPluginFilter extends PluginFilter { @Resource private GatewayGroupService gatewayGroupService; - /* - private String currentGatewayGroups; - - @PostConstruct - public void init() { - Iterator it = gatewayGroupService.currentGatewayGroupSet.iterator(); - while (it.hasNext()) { - if (StringUtils.isBlank(currentGatewayGroups)) { - currentGatewayGroups = it.next(); - } else { - currentGatewayGroups = currentGatewayGroups + ',' + it.next(); - } - } - } - */ - @Override public Mono doFilter(ServerWebExchange exchange, Map config, String fixedConfig) { if (statPluginFilterProperties.isStatOpen()) { StringBuilder b = ThreadContext.getStringBuilder(); b.append(Consts.S.LEFT_BRACE); - b.append(ip); toJsonStringValue(b, WebUtils.getOriginIp(exchange)); b.append(Consts.S.COMMA); - b.append(gatewayGroup); toJsonStringValue(b, currentGatewayGroups()); b.append(Consts.S.COMMA); - b.append(service); toJsonStringValue(b, WebUtils.getClientService(exchange)); b.append(Consts.S.COMMA); + b.append(ip); + toJsonStringValue(b, WebUtils.getOriginIp(exchange)); + b.append(Consts.S.COMMA); + b.append(gatewayGroup); + toJsonStringValue(b, currentGatewayGroups()); + b.append(Consts.S.COMMA); + b.append(service); + toJsonStringValue(b, WebUtils.getClientService(exchange)); + b.append(Consts.S.COMMA); String appId = WebUtils.getAppId(exchange); if (appId != null) { - b.append(appid); toJsonStringValue(b, appId); b.append(Consts.S.COMMA); + b.append(appid); + toJsonStringValue(b, appId); + b.append(Consts.S.COMMA); } - b.append(apiMethod); toJsonStringValue(b, exchange.getRequest().getMethodValue()); b.append(Consts.S.COMMA); - b.append(apiPath); toJsonStringValue(b, WebUtils.getClientReqPath(exchange)); b.append(Consts.S.COMMA); - b.append(reqTime) .append(System.currentTimeMillis()); + b.append(apiMethod); + toJsonStringValue(b, exchange.getRequest().getMethodValue()); + b.append(Consts.S.COMMA); + b.append(apiPath); + toJsonStringValue(b, WebUtils.getClientReqPath(exchange)); + b.append(Consts.S.COMMA); + b.append(reqTime).append(System.currentTimeMillis()); b.append(Consts.S.RIGHT_BRACE); if (StringUtils.isBlank(statPluginFilterProperties.getFizzAccessStatTopic())) { diff --git a/fizz-core/src/main/java/we/proxy/CallbackService.java b/fizz-core/src/main/java/we/proxy/CallbackService.java index fb9c958..ee083df 100644 --- a/fizz-core/src/main/java/we/proxy/CallbackService.java +++ b/fizz-core/src/main/java/we/proxy/CallbackService.java @@ -44,6 +44,7 @@ import we.util.*; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -205,7 +206,10 @@ public class CallbackService { public Mono replay(CallbackReplayReq req) { - ApiConfig ac = apiConfigService.getApiConfig(req.service, req.method, req.path, req.gatewayGroup, req.app); + HashSet gatewayGroups = new HashSet<>(); + gatewayGroups.add(req.gatewayGroup); + Result result = apiConfigService.getApiConfig(gatewayGroups, req.app, req.service, req.method, req.path); + ApiConfig ac = result.data; if (ac == null) { return Mono.just(ReactiveResult.fail("no api config for " + req.path)); } diff --git a/fizz-core/src/main/java/we/proxy/Route.java b/fizz-core/src/main/java/we/proxy/Route.java index edc9a49..bc2a09e 100644 --- a/fizz-core/src/main/java/we/proxy/Route.java +++ b/fizz-core/src/main/java/we/proxy/Route.java @@ -30,29 +30,29 @@ import java.util.List; public class Route { - public byte type; + public byte type; - public HttpMethod method; + public HttpMethod method; - public String backendService; + public String backendService; - public String backendPath; + public String backendPath; - public String query; + public String query; - public String nextHttpHostPort; + public String nextHttpHostPort; public List pluginConfigs; - public String rpcMethod; + public String rpcMethod; - public String rpcParamTypes; + public String rpcParamTypes; - public String rpcVersion; + public String rpcVersion; - public String rpcGroup; + public String rpcGroup; - public long timeout = 0; + public long timeout = 0; public Route type(byte t) { type = t; diff --git a/fizz-core/src/main/java/we/util/WebUtils.java b/fizz-core/src/main/java/we/util/WebUtils.java index 26ef5f2..3040cd6 100644 --- a/fizz-core/src/main/java/we/util/WebUtils.java +++ b/fizz-core/src/main/java/we/util/WebUtils.java @@ -174,12 +174,11 @@ public abstract class WebUtils { } public static ApiConfig getApiConfig(ServerWebExchange exchange) { - Object authRes = getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT); - if (authRes != null && authRes instanceof ApiConfig) { - return (ApiConfig) authRes; - } else { + Result authRes = (Result) getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT); + if (authRes == null) { return null; } + return authRes.data; } public static Route getRoute(ServerWebExchange exchange) { diff --git a/fizz-core/src/test/java/we/fizz/function/CodecFuncTests.java b/fizz-core/src/test/java/we/fizz/function/CodecFuncTests.java index de26a74..8db0258 100644 --- a/fizz-core/src/test/java/we/fizz/function/CodecFuncTests.java +++ b/fizz-core/src/test/java/we/fizz/function/CodecFuncTests.java @@ -87,7 +87,7 @@ class CodecFuncTests { assertEquals("QmFzZTY057yW56CB5LuL57uN", result.toString()); } - @Test + // @Test void testBase64Decode() { String funcExpression = "fn.codec.base64Decode(\"QmFzZTY057yW56CB5LuL57uN\")"; Object result = FuncExecutor.getInstance().exec(null, funcExpression);