@@ -12,13 +12,13 @@
|
||||
|
||||
<groupId>com.fizzgate</groupId>
|
||||
<artifactId>fizz-bootstrap</artifactId>
|
||||
<version>2.3.3-beta6</version>
|
||||
<version>2.3.4-beta1</version>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-framework.version>5.2.18.RELEASE</spring-framework.version>
|
||||
<spring-session-bom.version>Dragonfruit-SR3</spring-session-bom.version>
|
||||
<reactor-bom.version>Dysprosium-SR24</reactor-bom.version>
|
||||
<reactor-bom.version>Dysprosium-SR25</reactor-bom.version>
|
||||
<lettuce.version>5.3.7.RELEASE</lettuce.version>
|
||||
<netty.version>4.1.70.Final</netty.version>
|
||||
<httpcore.version>4.4.14</httpcore.version>
|
||||
|
||||
@@ -115,7 +115,7 @@ fizz:
|
||||
code-field: "msgCode"
|
||||
message-field: "message"
|
||||
|
||||
api.pairing:
|
||||
dedicated-line:
|
||||
server:
|
||||
enable: false
|
||||
client:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>fizz-gateway-community</artifactId>
|
||||
<groupId>com.fizzgate</groupId>
|
||||
<version>2.3.3-beta6</version>
|
||||
<version>2.3.4-beta1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>fizz-gateway-community</artifactId>
|
||||
<groupId>com.fizzgate</groupId>
|
||||
<version>2.3.3-beta6</version>
|
||||
<version>2.3.4-beta1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
|
||||
import we.util.JacksonUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class ApiPairingDocSet {
|
||||
|
||||
public static final int DELETED = 1;
|
||||
|
||||
public int isDeleted = 0;
|
||||
|
||||
public long id;
|
||||
|
||||
public String name;
|
||||
|
||||
public String description;
|
||||
|
||||
public List<ApiPairingDoc> docs = Collections.emptyList();
|
||||
|
||||
public Set<String> appIds = Collections.emptySet();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ApiPairingDocSet that = (ApiPairingDocSet) o;
|
||||
return id == that.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JacksonUtils.writeValueAsString(this);
|
||||
}
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.config.AggregateRedisConfig;
|
||||
import we.config.SystemConfig;
|
||||
import we.plugin.auth.ApiConfig;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.Result;
|
||||
import we.util.UrlTransformUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_SERVER_ENABLE, havingValue = "true")
|
||||
@Service
|
||||
public class ApiPairingDocSetService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiPairingDocSetService.class);
|
||||
|
||||
private Map<Long /* doc set id */, ApiPairingDocSet> docSetMap = new HashMap<>(64);
|
||||
|
||||
private Map<String /* app id */, Set<ApiPairingDocSet>> appDocSetMap = new HashMap<>(64);
|
||||
|
||||
private Map<String /* service */, Set<ApiPairingDocSet>> serviceExistsInDocSetMap = new HashMap<>(64);
|
||||
|
||||
private Map<Object /* method */, Map<String /* path pattern */, Set<ApiPairingDocSet>>> methodPathExistsInDocSetMap = new HashMap<>();
|
||||
|
||||
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
|
||||
private ReactiveStringRedisTemplate rt;
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws Throwable {
|
||||
Result<?> result = initApiPairingDocSet();
|
||||
if (result.code == Result.FAIL) {
|
||||
throw new RuntimeException(result.msg, result.t);
|
||||
}
|
||||
result = lsnApiPairingDocSetChange();
|
||||
if (result.code == Result.FAIL) {
|
||||
throw new RuntimeException(result.msg, result.t);
|
||||
}
|
||||
}
|
||||
|
||||
private Result<?> initApiPairingDocSet() {
|
||||
Result<?> result = Result.succ();
|
||||
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_api_pairing_doc");
|
||||
resources.collectList()
|
||||
.defaultIfEmpty(Collections.emptyList())
|
||||
.flatMap(
|
||||
es -> {
|
||||
if (!es.isEmpty()) {
|
||||
String json = null;
|
||||
try {
|
||||
for (Map.Entry<Object, Object> e : es) {
|
||||
json = (String) e.getValue();
|
||||
ApiPairingDocSet docSet = JacksonUtils.readValue(json, ApiPairingDocSet.class);
|
||||
updateDocSetDataStruct(docSet);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "init api pairing doc set error, doc set: " + json;
|
||||
result.t = t;
|
||||
}
|
||||
} else {
|
||||
log.info("no api pairing doc set");
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
)
|
||||
.onErrorReturn(
|
||||
throwable -> {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "init api pairing doc set error";
|
||||
result.t = throwable;
|
||||
return true;
|
||||
},
|
||||
result
|
||||
)
|
||||
.block();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Result<?> lsnApiPairingDocSetChange() {
|
||||
Result<?> result = Result.succ();
|
||||
String channel = "fizz_api_pairing_doc_channel";
|
||||
rt.listenToChannel(channel)
|
||||
.doOnError(
|
||||
t -> {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "lsn error, channel: " + channel;
|
||||
result.t = t;
|
||||
log.error("lsn channel {} error", channel, t);
|
||||
}
|
||||
)
|
||||
.doOnSubscribe(
|
||||
s -> {
|
||||
log.info("success to lsn on {}", channel);
|
||||
}
|
||||
)
|
||||
.doOnNext(
|
||||
msg -> {
|
||||
String message = msg.getMessage();
|
||||
try {
|
||||
ApiPairingDocSet docSet = JacksonUtils.readValue(message, ApiPairingDocSet.class);
|
||||
updateDocSetDataStruct(docSet);
|
||||
} catch (Throwable t) {
|
||||
log.error("update api pairing doc set error, {}", message, t);
|
||||
}
|
||||
}
|
||||
)
|
||||
.subscribe();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void updateDocSetDataStruct(ApiPairingDocSet docSet) {
|
||||
if (docSet.isDeleted == ApiPairingDocSet.DELETED) {
|
||||
docSetMap.remove(docSet.id);
|
||||
|
||||
for (String appId : docSet.appIds) {
|
||||
Set<ApiPairingDocSet> dss = appDocSetMap.get(appId);
|
||||
if (dss != null) {
|
||||
dss.remove(docSet);
|
||||
if (dss.isEmpty()) {
|
||||
appDocSetMap.remove(appId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ApiPairingDoc doc : docSet.docs) {
|
||||
Set<ApiPairingDocSet> dss = serviceExistsInDocSetMap.get(doc.service);
|
||||
if (dss != null) {
|
||||
dss.remove(docSet);
|
||||
if (dss.isEmpty()) {
|
||||
serviceExistsInDocSetMap.remove(doc.service);
|
||||
}
|
||||
}
|
||||
for (Api api : doc.apis) {
|
||||
Map<String, Set<ApiPairingDocSet>> pathDocSetMap = methodPathExistsInDocSetMap.get(api.method);
|
||||
if (pathDocSetMap != null) {
|
||||
dss = pathDocSetMap.get(api.path);
|
||||
if (dss != null) {
|
||||
dss.remove(docSet);
|
||||
if (dss.isEmpty()) {
|
||||
pathDocSetMap.remove(api.path);
|
||||
if (pathDocSetMap.isEmpty()) {
|
||||
methodPathExistsInDocSetMap.remove(api.method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("delete doc set: {}", docSet);
|
||||
|
||||
} else {
|
||||
docSetMap.put(docSet.id, docSet);
|
||||
docSet.appIds.forEach(
|
||||
appId -> {
|
||||
Set<ApiPairingDocSet> dss = appDocSetMap.computeIfAbsent(appId, k -> new HashSet<>());
|
||||
dss.add(docSet);
|
||||
}
|
||||
);
|
||||
docSet.docs.forEach(
|
||||
doc -> {
|
||||
Set<ApiPairingDocSet> dss = serviceExistsInDocSetMap.computeIfAbsent(doc.service, k -> new HashSet<>());
|
||||
dss.add(docSet);
|
||||
for (Api api : doc.apis) {
|
||||
Map<String, Set<ApiPairingDocSet>> pathDocSetMap = methodPathExistsInDocSetMap.computeIfAbsent(api.method, k -> new HashMap<>());
|
||||
dss = pathDocSetMap.computeIfAbsent(api.path, k -> new HashSet<>());
|
||||
dss.add(docSet);
|
||||
}
|
||||
}
|
||||
);
|
||||
log.info("update doc set: {}", docSet);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Long, ApiPairingDocSet> getDocSetMap() {
|
||||
return docSetMap;
|
||||
}
|
||||
|
||||
public ApiPairingDocSet get(long id) {
|
||||
return docSetMap.get(id);
|
||||
}
|
||||
|
||||
public Map<String, Set<ApiPairingDocSet>> getAppDocSetMap() {
|
||||
return appDocSetMap;
|
||||
}
|
||||
|
||||
public Map<String, Set<ApiPairingDocSet>> getServiceExistsInDocSetMap() {
|
||||
return serviceExistsInDocSetMap;
|
||||
}
|
||||
|
||||
public Map<Object, Map<String, Set<ApiPairingDocSet>>> getMethodPathExistsInDocSetMap() {
|
||||
return methodPathExistsInDocSetMap;
|
||||
}
|
||||
|
||||
public boolean existsDocSetMatch(String appId, HttpMethod method, String service, String path) {
|
||||
Set<ApiPairingDocSet> appDocSets = appDocSetMap.get(appId);
|
||||
if (appDocSets == null) {
|
||||
return false;
|
||||
}
|
||||
Set<ApiPairingDocSet> serviceDocSets = serviceExistsInDocSetMap.get(service);
|
||||
if (serviceDocSets == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<ApiPairingDocSet> s = new HashSet<>();
|
||||
Map<String, Set<ApiPairingDocSet>> pathDocSetMap = methodPathExistsInDocSetMap.get(method);
|
||||
if (pathDocSetMap != null) {
|
||||
checkPathPattern(pathDocSetMap, path, s);
|
||||
}
|
||||
pathDocSetMap = methodPathExistsInDocSetMap.get(ApiConfig.ALL_METHOD);
|
||||
if (pathDocSetMap != null) {
|
||||
checkPathPattern(pathDocSetMap, path, s);
|
||||
}
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s.retainAll(appDocSets);
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
s.retainAll(serviceDocSets);
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkPathPattern(Map<String, Set<ApiPairingDocSet>> pathDocSetMap, String path, Set<ApiPairingDocSet> result) {
|
||||
Set<Map.Entry<String, Set<ApiPairingDocSet>>> entries = pathDocSetMap.entrySet();
|
||||
for (Map.Entry<String, Set<ApiPairingDocSet>> entry : entries) {
|
||||
String pathPattern = entry.getKey();
|
||||
if (pathPattern.equals(path) || UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
|
||||
result.addAll(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
|
||||
import we.util.JacksonUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class AppApiPairingDocSet {
|
||||
|
||||
public long id;
|
||||
|
||||
public String name;
|
||||
|
||||
public String description;
|
||||
|
||||
public Set<String> services;
|
||||
|
||||
public boolean enabled;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JacksonUtils.writeValueAsString(this);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ public class FizzMangerConfig {
|
||||
|
||||
public String managerUrl;
|
||||
|
||||
public String pairPath = "/fizz-manager/dedicated-line/pair";
|
||||
|
||||
public String docPathPrefix = "/fizz-manager/open-doc/open-doc-show/pair";
|
||||
|
||||
@PostConstruct
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import we.fizz.ConfigLoader;
|
||||
import we.plugin.auth.ApiConfigService;
|
||||
import we.plugin.auth.ApiConifg2appsService;
|
||||
import we.plugin.auth.ApiConfig2appsService;
|
||||
import we.plugin.auth.AppService;
|
||||
import we.plugin.auth.GatewayGroupService;
|
||||
import we.proxy.RpcInstanceService;
|
||||
@@ -33,7 +33,7 @@ import javax.annotation.Resource;
|
||||
/**
|
||||
* refresh config local cache config
|
||||
* @see ApiConfigService#refreshLocalCache() refresh api config local cache
|
||||
* @see ApiConifg2appsService#refreshLocalCache() refresh api config to apps local cache
|
||||
* @see ApiConfig2appsService#refreshLocalCache() refresh api config to apps local cache
|
||||
* @see ConfigLoader#refreshLocalCache() refresh aggregate config local cache
|
||||
* @see GatewayGroupService#refreshLocalCache() refresh gateway group local cache
|
||||
* @see AppService#refreshLocalCache() refresh app local cache
|
||||
@@ -56,7 +56,7 @@ public class RefreshLocalCacheConfig {
|
||||
private ApiConfigService apiConfigService;
|
||||
|
||||
@Resource
|
||||
private ApiConifg2appsService apiConifg2appsService;
|
||||
private ApiConfig2appsService apiConfig2AppsService;
|
||||
|
||||
@Resource
|
||||
private GatewayGroupService gatewayGroupService;
|
||||
@@ -88,7 +88,7 @@ public class RefreshLocalCacheConfig {
|
||||
if (refreshLocalCacheConfigProperties.isApiConfig2AppsCacheRefreshEnabled()) {
|
||||
LOGGER.debug("refresh api config to apps local cache");
|
||||
try {
|
||||
apiConifg2appsService.refreshLocalCache();
|
||||
apiConfig2AppsService.refreshLocalCache();
|
||||
} catch (Throwable t) {
|
||||
LOGGER.warn("refresh api config to apps local cache exception", t);
|
||||
}
|
||||
|
||||
@@ -42,22 +42,26 @@ public class SystemConfig {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SystemConfig.class);
|
||||
|
||||
public static final String DEFAULT_GATEWAY_PREFIX = "/proxy";
|
||||
public static final String DEFAULT_GATEWAY_TEST_PREFIX = "/_proxytest";
|
||||
public static final String DEFAULT_GATEWAY_TEST = "_proxytest";
|
||||
public static final String DEFAULT_GATEWAY_TEST_PREFIX0 = "/_proxytest/";
|
||||
public static final String DEFAULT_GATEWAY_PREFIX = "/proxy";
|
||||
public static final String DEFAULT_GATEWAY_TEST_PREFIX = "/_proxytest";
|
||||
public static final String DEFAULT_GATEWAY_TEST = "_proxytest";
|
||||
public static final String DEFAULT_GATEWAY_TEST_PREFIX0 = "/_proxytest/";
|
||||
|
||||
public static boolean FIZZ_ERR_RESP_HTTP_STATUS_ENABLE = true;
|
||||
public static String FIZZ_ERR_RESP_CODE_FIELD = "msgCode";
|
||||
public static String FIZZ_ERR_RESP_MSG_FIELD = "message";
|
||||
public static boolean FIZZ_ERR_RESP_HTTP_STATUS_ENABLE = true;
|
||||
public static String FIZZ_ERR_RESP_CODE_FIELD = "msgCode";
|
||||
public static String FIZZ_ERR_RESP_MSG_FIELD = "message";
|
||||
|
||||
public static final String FIZZ_APP_ID = "fizz-appid";
|
||||
public static final String FIZZ_SIGN = "fizz-sign";
|
||||
public static final String FIZZ_TIMESTAMP = "fizz-ts";
|
||||
public static final String FIZZ_DL_ID = "fizz-dl-id";
|
||||
public static final String FIZZ_DL_SIGN = "fizz-dl-sign";
|
||||
public static final String FIZZ_DL_TS = "fizz-dl-ts";
|
||||
|
||||
public static final String FIZZ_API_PAIRING_SERVER_ENABLE = "fizz.api.pairing.server.enable";
|
||||
public static final String FIZZ_API_PAIRING_CLIENT_PREFIX = "fizz.api.pairing.client";
|
||||
public static final String FIZZ_API_PAIRING_CLIENT_ENABLE = "fizz.api.pairing.client.enable";
|
||||
public static final String FIZZ_APP_ID = "fizz-appid";
|
||||
public static final String FIZZ_SIGN = "fizz-sign";
|
||||
public static final String FIZZ_TIMESTAMP = "fizz-ts";
|
||||
|
||||
public static final String FIZZ_DEDICATED_LINE_SERVER_ENABLE = "fizz.dedicated-line.server.enable";
|
||||
public static final String FIZZ_DEDICATED_LINE_CLIENT_PREFIX = "fizz.dedicated-line.client";
|
||||
public static final String FIZZ_DEDICATED_LINE_CLIENT_ENABLE = "fizz.dedicated-line.client.enable";
|
||||
|
||||
private String gatewayPrefix = DEFAULT_GATEWAY_PREFIX;
|
||||
|
||||
@@ -98,32 +102,32 @@ public class SystemConfig {
|
||||
|
||||
|
||||
|
||||
@Value("${fizz.api.pairing.client.request.timeliness:300}")
|
||||
private int fizzApiPairingRequestTimeliness = 300; // unit: sec
|
||||
@Value("${fizz.dedicated-line.client.request.timeliness:300}")
|
||||
private int fizzDedicatedLineClientRequestTimeliness = 300; // unit: sec
|
||||
|
||||
@Value("${fizz.api.pairing.client.request.timeout:0}")
|
||||
private int fizzApiPairingRequestTimeout = 0; // mills
|
||||
@Value("${fizz.dedicated-line.client.request.timeout:0}")
|
||||
private int fizzDedicatedLineClientRequestTimeout = 0; // mills
|
||||
|
||||
@Value("${fizz.api.pairing.client.request.retry-count:0}")
|
||||
private int fizzApiPairingRequestRetryCount = 0;
|
||||
@Value("${fizz.dedicated-line.client.request.retry-count:0}")
|
||||
private int fizzDedicatedLineClientRequestRetryCount = 0;
|
||||
|
||||
@Value("${fizz.api.pairing.client.request.retry-interval:0}")
|
||||
private int fizzApiPairingRequestRetryInterval = 0; // mills
|
||||
@Value("${fizz.dedicated-line.client.request.retry-interval:0}")
|
||||
private int fizzDedicatedLineClientRequestRetryInterval = 0; // mills
|
||||
|
||||
public int fizzApiPairingRequestTimeout() {
|
||||
return fizzApiPairingRequestTimeout;
|
||||
public int fizzDedicatedLineClientRequestTimeout() {
|
||||
return fizzDedicatedLineClientRequestTimeout;
|
||||
}
|
||||
|
||||
public int fizzApiPairingRequestRetryCount() {
|
||||
return fizzApiPairingRequestRetryCount;
|
||||
public int fizzDedicatedLineClientRequestRetryCount() {
|
||||
return fizzDedicatedLineClientRequestRetryCount;
|
||||
}
|
||||
|
||||
public int fizzApiPairingRequestRetryInterval() {
|
||||
return fizzApiPairingRequestRetryInterval;
|
||||
public int fizzDedicatedLineClientRequestRetryInterval() {
|
||||
return fizzDedicatedLineClientRequestRetryInterval;
|
||||
}
|
||||
|
||||
public int fizzApiPairingRequestTimeliness() {
|
||||
return fizzApiPairingRequestTimeliness;
|
||||
public int fizzDedicatedLineClientRequestTimeliness() {
|
||||
return fizzDedicatedLineClientRequestTimeliness;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.global_resource.GlobalResourceService;
|
||||
import we.plugin.auth.ApiConfig2appsService;
|
||||
import we.plugin.auth.ApiConfigService;
|
||||
import we.plugin.auth.ApiConifg2appsService;
|
||||
import we.plugin.auth.AppService;
|
||||
import we.plugin.auth.GatewayGroupService;
|
||||
import we.stats.ratelimit.ResourceRateLimitConfigService;
|
||||
@@ -53,7 +53,7 @@ public class CacheCheckController {
|
||||
private ResourceRateLimitConfigService resourceRateLimitConfigService;
|
||||
|
||||
@Resource
|
||||
private ApiConifg2appsService apiConifg2appsService;
|
||||
private ApiConfig2appsService apiConfig2AppsService;
|
||||
|
||||
@Resource
|
||||
private GlobalResourceService globalResourceService;
|
||||
@@ -74,7 +74,7 @@ public class CacheCheckController {
|
||||
}
|
||||
|
||||
@GetMapping("/serviceConfigs")
|
||||
public Mono<String> apiConfigs(ServerWebExchange exchange) {
|
||||
public Mono<String> serviceConfigs(ServerWebExchange exchange) {
|
||||
return Mono.just(JacksonUtils.writeValueAsString(apiConfigService.serviceConfigMap));
|
||||
}
|
||||
|
||||
@@ -85,11 +85,11 @@ public class CacheCheckController {
|
||||
|
||||
@GetMapping("/apiConfig2appsConfigs")
|
||||
public Mono<String> apiConfig2appsConfigs(ServerWebExchange exchange) {
|
||||
return Mono.just(JacksonUtils.writeValueAsString(apiConifg2appsService.getApiConfig2appsMap()));
|
||||
return Mono.just(JacksonUtils.writeValueAsString(apiConfig2AppsService.getApiConfig2appsMap()));
|
||||
}
|
||||
|
||||
@GetMapping("/globalResources")
|
||||
public Mono<String> dicts(ServerWebExchange exchange) {
|
||||
public Mono<String> globalResources(ServerWebExchange exchange) {
|
||||
return Mono.just(JacksonUtils.writeValueAsString(globalResourceService.getResourceMap()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import we.util.JacksonUtils;
|
||||
|
||||
@@ -26,11 +26,15 @@ import java.util.List;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class ApiPairingDoc {
|
||||
public class ApiDoc {
|
||||
|
||||
public String service;
|
||||
|
||||
public List<Api> apis = Collections.emptyList();
|
||||
public List<MethodAndPath> methodAndPaths = Collections.emptyList();
|
||||
|
||||
public void setApis(List<MethodAndPath> methodAndPaths) {
|
||||
this.methodAndPaths = methodAndPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
80
fizz-core/src/main/java/we/dedicated_line/DedicatedLine.java
Normal file
80
fizz-core/src/main/java/we/dedicated_line/DedicatedLine.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.dedicated_line;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import we.util.JacksonUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class DedicatedLine {
|
||||
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public String pairCodeId;
|
||||
|
||||
public String secretKey;
|
||||
|
||||
public String customConfig;
|
||||
|
||||
public List<ApiDoc> apiDocs = Collections.emptyList();
|
||||
|
||||
@JsonIgnore
|
||||
public Map<String/*service*/,
|
||||
Map<Object/*method*/, Set<String/*pathPattern*/>>
|
||||
>
|
||||
apiDocMap = Collections.emptyMap();
|
||||
|
||||
public Set<String> servicesWithoutApiDocs = Collections.emptySet();
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDocs(List<ApiDoc> docs) {
|
||||
apiDocs = docs;
|
||||
if (CollectionUtils.isEmpty(apiDocs)) {
|
||||
apiDocMap = Collections.emptyMap();
|
||||
} else {
|
||||
apiDocMap = new HashMap<>();
|
||||
for (ApiDoc apiDoc : apiDocs) {
|
||||
Map<Object, Set<String>> methodPathsMap = apiDocMap.computeIfAbsent(apiDoc.service, k -> new HashMap<>());
|
||||
for (MethodAndPath methodAndPath : apiDoc.methodAndPaths) {
|
||||
Set<String> paths = methodPathsMap.computeIfAbsent(methodAndPath.method, k -> new HashSet<>());
|
||||
paths.add(methodAndPath.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setServices(Set<String> services) {
|
||||
servicesWithoutApiDocs = services;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JacksonUtils.writeValueAsString(this);
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -36,37 +34,31 @@ import reactor.core.publisher.Mono;
|
||||
import we.config.FizzMangerConfig;
|
||||
import we.config.SystemConfig;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.plugin.auth.App;
|
||||
import we.plugin.auth.AppService;
|
||||
import we.proxy.FizzWebClient;
|
||||
import we.util.*;
|
||||
import we.util.DateTimeUtils;
|
||||
import we.util.Result;
|
||||
import we.util.ThreadContext;
|
||||
import we.util.WebUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_SERVER_ENABLE, havingValue = "true")
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_SERVER_ENABLE, havingValue = "true")
|
||||
@RestController
|
||||
@RequestMapping(SystemConfig.DEFAULT_GATEWAY_PREFIX + "/_fizz-pairing")
|
||||
public class ApiPairingController {
|
||||
@RequestMapping(SystemConfig.DEFAULT_GATEWAY_PREFIX + "/_fizz-dedicated-line")
|
||||
public class DedicatedLineController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiPairingController.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineController.class);
|
||||
|
||||
@Resource
|
||||
private SystemConfig systemConfig;
|
||||
|
||||
@Resource
|
||||
private AppService appService;
|
||||
|
||||
@Resource
|
||||
private ApiPairingDocSetService apiPairingDocSetService;
|
||||
private DedicatedLineService dedicatedLineService;
|
||||
|
||||
@Resource
|
||||
private FizzMangerConfig fizzMangerConfig;
|
||||
@@ -75,23 +67,19 @@ public class ApiPairingController {
|
||||
private FizzWebClient fizzWebClient;
|
||||
|
||||
private Result<?> auth(ServerWebExchange exchange) {
|
||||
String appId = WebUtils.getAppId(exchange);
|
||||
if (appId == null) {
|
||||
return Result.fail("no app info in request");
|
||||
}
|
||||
App app = appService.getApp(appId);
|
||||
if (app == null) {
|
||||
return Result.fail(appId + " not exists");
|
||||
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
|
||||
if (dedicatedLineId == null) {
|
||||
return Result.fail("no dedicated line id in request");
|
||||
}
|
||||
|
||||
String timestamp = WebUtils.getTimestamp(exchange);
|
||||
String timestamp = WebUtils.getDedicatedLineTimestamp(exchange);
|
||||
if (timestamp == null) {
|
||||
return Result.fail("no timestamp in request");
|
||||
}
|
||||
try {
|
||||
long ts = Long.parseLong(timestamp);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
long timeliness = systemConfig.fizzApiPairingRequestTimeliness();
|
||||
long timeliness = systemConfig.fizzDedicatedLineClientRequestTimeliness();
|
||||
long start = DateTimeUtils.toMillis(now.minusSeconds(timeliness));
|
||||
long end = DateTimeUtils.toMillis(now.plusSeconds (timeliness));
|
||||
if (start <= ts && ts <= end) {
|
||||
@@ -100,17 +88,19 @@ public class ApiPairingController {
|
||||
return Result.fail("request timestamp invalid");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return Result.fail("request timestamp invalid");
|
||||
return Result.fail("request timestamp format invalid");
|
||||
}
|
||||
|
||||
String sign = WebUtils.getSign(exchange);
|
||||
String sign = WebUtils.getDedicatedLineSign(exchange);
|
||||
if (sign == null) {
|
||||
return Result.fail("no sign in request");
|
||||
}
|
||||
boolean equals = ApiPairingUtils.checkSign(appId, timestamp, app.secretkey, sign);
|
||||
|
||||
String pairCodeSecretKey = dedicatedLineService.getPairCodeSecretKey(dedicatedLineId);
|
||||
boolean equals = DedicatedLineUtils.checkSign(dedicatedLineId, timestamp, pairCodeSecretKey, sign);
|
||||
if (!equals) {
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
log.warn("{} request authority: app {}, timestamp {}, sign {} invalid", traceId, appId, timestamp, sign, LogService.BIZ_ID, traceId);
|
||||
log.warn("{} request authority: dedicated line id {}, timestamp {}, sign {} invalid", traceId, dedicatedLineId, timestamp, sign, LogService.BIZ_ID, traceId);
|
||||
return Result.fail("request sign invalid");
|
||||
}
|
||||
return Result.succ();
|
||||
@@ -118,37 +108,33 @@ public class ApiPairingController {
|
||||
|
||||
@GetMapping("/pair")
|
||||
public Mono<Void> pair(ServerWebExchange exchange) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
Result<?> auth = auth(exchange);
|
||||
if (auth.code == Result.SUCC) {
|
||||
String appId = WebUtils.getAppId(exchange);
|
||||
List<AppApiPairingDocSet> docs = getAppDocSet(appId);
|
||||
String docsJson = JacksonUtils.writeValueAsString(docs);
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
return response.writeWith(Mono.just(response.bufferFactory().wrap(docsJson.getBytes())));
|
||||
} else {
|
||||
return WebUtils.response(response, HttpStatus.FORBIDDEN, null, auth.msg);
|
||||
String managerUrl = fizzMangerConfig.managerUrl;
|
||||
if (managerUrl == null) {
|
||||
return WebUtils.response(response, HttpStatus.INTERNAL_SERVER_ERROR, null, "no fizz manager url config");
|
||||
}
|
||||
}
|
||||
String address = managerUrl + fizzMangerConfig.pairPath;
|
||||
|
||||
private List<AppApiPairingDocSet> getAppDocSet(String appId) {
|
||||
Map<Long, ApiPairingDocSet> docSetMap = apiPairingDocSetService.getDocSetMap();
|
||||
ArrayList<AppApiPairingDocSet> result = ThreadContext.getArrayList();
|
||||
for (Map.Entry<Long, ApiPairingDocSet> entry : docSetMap.entrySet()) {
|
||||
ApiPairingDocSet ds = entry.getValue();
|
||||
AppApiPairingDocSet appDocSet = new AppApiPairingDocSet();
|
||||
appDocSet.id = ds.id;
|
||||
appDocSet.name = ds.name;
|
||||
appDocSet.description = ds.description;
|
||||
appDocSet.services = ds.docs.stream().map(d -> d.service).collect(Collectors.toSet());
|
||||
appDocSet.enabled = false;
|
||||
if (ds.appIds.contains(appId)) {
|
||||
appDocSet.enabled = true;
|
||||
}
|
||||
result.add(appDocSet);
|
||||
}
|
||||
return result;
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send(traceId, request.getMethod(), address, request.getHeaders(), null);
|
||||
return
|
||||
remoteResponseMono.flatMap(
|
||||
remoteResp -> {
|
||||
response.setStatusCode(remoteResp.statusCode());
|
||||
HttpHeaders respHeaders = response.getHeaders();
|
||||
HttpHeaders remoteRespHeaders = remoteResp.headers().asHttpHeaders();
|
||||
respHeaders.putAll(remoteRespHeaders);
|
||||
if (log.isDebugEnabled()) {
|
||||
StringBuilder sb = ThreadContext.getStringBuilder();
|
||||
WebUtils.response2stringBuilder(traceId, remoteResp, sb);
|
||||
log.debug(sb.toString(), LogService.BIZ_ID, traceId);
|
||||
}
|
||||
return response.writeWith ( remoteResp.body(BodyExtractors.toDataBuffers()) )
|
||||
.doOnError ( throwable -> cleanup(remoteResp) )
|
||||
.doOnCancel( () -> cleanup(remoteResp) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/doc/**")
|
||||
@@ -166,7 +152,7 @@ public class ApiPairingController {
|
||||
String address = managerUrl + fizzMangerConfig.docPathPrefix + uri.substring(dp + 3);
|
||||
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send(traceId, request.getMethod(), address, request.getHeaders(), request.getBody());
|
||||
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send(traceId, request.getMethod(), address, request.getHeaders(), null);
|
||||
return
|
||||
remoteResponseMono.flatMap(
|
||||
remoteResp -> {
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -51,11 +51,11 @@ import java.util.Set;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
class FizzApiPairingHttpHandler implements HttpHandler {
|
||||
class DedicatedLineHttpHandler implements HttpHandler {
|
||||
|
||||
private static final String disconnected_client_log_category = "DisconnectedClient";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FizzApiPairingHttpHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineHttpHandler.class);
|
||||
|
||||
private static final Logger lostClientLog = LoggerFactory.getLogger(disconnected_client_log_category);
|
||||
|
||||
@@ -69,19 +69,19 @@ class FizzApiPairingHttpHandler implements HttpHandler {
|
||||
|
||||
private SystemConfig systemConfig;
|
||||
private FizzWebClient fizzWebClient;
|
||||
private ApiPairingInfoService apiPairingInfoService;
|
||||
private DedicatedLineInfoService dedicatedLineInfoService;
|
||||
|
||||
public FizzApiPairingHttpHandler(ReactiveWebServerApplicationContext applicationContext, WebSessionManager sessionManager, ServerCodecConfigurer codecConfigurer,
|
||||
LocaleContextResolver localeContextResolver, ForwardedHeaderTransformer forwardedHeaderTransformer) {
|
||||
public DedicatedLineHttpHandler(ReactiveWebServerApplicationContext applicationContext, WebSessionManager sessionManager, ServerCodecConfigurer codecConfigurer,
|
||||
LocaleContextResolver localeContextResolver, ForwardedHeaderTransformer forwardedHeaderTransformer) {
|
||||
|
||||
this.sessionManager = sessionManager;
|
||||
this.serverCodecConfigurer = codecConfigurer;
|
||||
this.localeContextResolver = localeContextResolver;
|
||||
this.forwardedHeaderTransformer = forwardedHeaderTransformer;
|
||||
|
||||
systemConfig = applicationContext.getBean(SystemConfig.class);
|
||||
fizzWebClient = applicationContext.getBean(FizzWebClient.class);
|
||||
apiPairingInfoService = applicationContext.getBean(ApiPairingInfoService.class);
|
||||
systemConfig = applicationContext.getBean(SystemConfig.class);
|
||||
fizzWebClient = applicationContext.getBean(FizzWebClient.class);
|
||||
dedicatedLineInfoService = applicationContext.getBean(DedicatedLineInfoService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,14 +105,14 @@ class FizzApiPairingHttpHandler implements HttpHandler {
|
||||
String path = requestURI.getPath();
|
||||
int secFS = path.indexOf(Consts.S.FORWARD_SLASH, 1);
|
||||
String service = path.substring(1, secFS);
|
||||
ApiPairingInfo apiPairingInfo = apiPairingInfoService.get(service);
|
||||
if (apiPairingInfo == null) {
|
||||
log.warn("{}{} service no api pairing info", logPrefix, service);
|
||||
return WebUtils.response(response, HttpStatus.FORBIDDEN, null, service + " service no api pairing info").then(response.setComplete());
|
||||
DedicatedLineInfo dedicatedLineInfo = dedicatedLineInfoService.get(service);
|
||||
if (dedicatedLineInfo == null) {
|
||||
log.warn("{}{} service no dedicated line info", logPrefix, service);
|
||||
return WebUtils.response(response, HttpStatus.FORBIDDEN, null, service + " service no dedicated line info").then(response.setComplete());
|
||||
}
|
||||
|
||||
StringBuilder b = ThreadContext.getStringBuilder();
|
||||
b.append(apiPairingInfo.url).append(path);
|
||||
b.append(dedicatedLineInfo.url).append(path);
|
||||
String qry = requestURI.getQuery();
|
||||
if (StringUtils.hasText(qry)) {
|
||||
if (org.apache.commons.lang3.StringUtils.indexOfAny(qry, Consts.S.LEFT_BRACE, Consts.S.FORWARD_SLASH, Consts.S.HASH) > 0) {
|
||||
@@ -120,22 +120,23 @@ class FizzApiPairingHttpHandler implements HttpHandler {
|
||||
}
|
||||
b.append(Consts.S.QUESTION).append(qry);
|
||||
}
|
||||
String targetUrl = b.toString();
|
||||
String appId = apiPairingInfo.appId;
|
||||
String secretKey = apiPairingInfo.secretKey;
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String sign = ApiPairingUtils.sign(appId, timestamp, secretKey);
|
||||
String targetUrl = b.toString();
|
||||
String pairCodeId = dedicatedLineInfo.pairCodeId;
|
||||
String secretKey = dedicatedLineInfo.secretKey;
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String sign = DedicatedLineUtils.sign(pairCodeId, timestamp, secretKey);
|
||||
|
||||
HttpHeaders writableHttpHeaders = HttpHeaders.writableHttpHeaders(request.getHeaders());
|
||||
writableHttpHeaders.set(SystemConfig.FIZZ_APP_ID, appId);
|
||||
writableHttpHeaders.set(SystemConfig.FIZZ_TIMESTAMP, timestamp);
|
||||
writableHttpHeaders.set(SystemConfig.FIZZ_SIGN, sign);
|
||||
writableHttpHeaders.set(SystemConfig.FIZZ_DL_ID, pairCodeId);
|
||||
writableHttpHeaders.set(SystemConfig.FIZZ_DL_TS, timestamp);
|
||||
writableHttpHeaders.set(SystemConfig.FIZZ_DL_SIGN, sign);
|
||||
|
||||
int requestTimeout = systemConfig.fizzApiPairingRequestTimeout();
|
||||
int retryCount = systemConfig.fizzApiPairingRequestRetryCount();
|
||||
int retryInterval = systemConfig.fizzApiPairingRequestRetryInterval();
|
||||
int requestTimeout = systemConfig.fizzDedicatedLineClientRequestTimeout();
|
||||
int retryCount = systemConfig.fizzDedicatedLineClientRequestRetryCount();
|
||||
int retryInterval = systemConfig.fizzDedicatedLineClientRequestRetryInterval();
|
||||
|
||||
try {
|
||||
// TODO: 如果有请求体,则对请求体加密
|
||||
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send( request.getId(), request.getMethod(), targetUrl, writableHttpHeaders, request.getBody(),
|
||||
requestTimeout, retryCount, retryInterval );
|
||||
|
||||
@@ -150,6 +151,7 @@ class FizzApiPairingHttpHandler implements HttpHandler {
|
||||
WebUtils.response2stringBuilder(logPrefix, remoteResp, sb);
|
||||
log.debug(sb.toString());
|
||||
}
|
||||
// TODO: 如果有响应体,则对响应体解密;响应可能是页面、表单、文件上传的结果、图片等
|
||||
return response.writeWith ( remoteResp.body(BodyExtractors.toDataBuffers()) )
|
||||
.doOnError ( throwable -> cleanup(remoteResp) )
|
||||
.doOnCancel( () -> cleanup(remoteResp) );
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import we.util.JacksonUtils;
|
||||
|
||||
@@ -26,22 +26,26 @@ import java.util.List;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class ApiPairingInfo {
|
||||
public class DedicatedLineInfo {
|
||||
|
||||
public static final int DELETED = 1;
|
||||
|
||||
public int isDeleted = 0;
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public String id; // uuid
|
||||
|
||||
public String url;
|
||||
|
||||
public String appId;
|
||||
public String pairCodeId;
|
||||
|
||||
public String secretKey;
|
||||
|
||||
public List<String> services = Collections.emptyList();
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JacksonUtils.writeValueAsString(this);
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -39,20 +39,20 @@ import java.util.Map;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_CLIENT_ENABLE, havingValue = "true")
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_ENABLE, havingValue = "true")
|
||||
@Service
|
||||
public class ApiPairingInfoService {
|
||||
public class DedicatedLineInfoService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiPairingInfoService.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineInfoService.class);
|
||||
|
||||
private Map<String , ApiPairingInfo> serviceApiPairingInfoMap = new HashMap<>(64);
|
||||
private Map<String , DedicatedLineInfo> serviceDedicatedLineInfoMap = new HashMap<>(32);
|
||||
|
||||
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
|
||||
private ReactiveStringRedisTemplate rt;
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws Throwable {
|
||||
Result<?> result = initApiPairingInfo();
|
||||
Result<?> result = initDedicatedLineInfo();
|
||||
if (result.code == Result.FAIL) {
|
||||
throw new RuntimeException(result.msg, result.t);
|
||||
}
|
||||
@@ -62,9 +62,9 @@ public class ApiPairingInfoService {
|
||||
}
|
||||
}
|
||||
|
||||
private Result<?> initApiPairingInfo() {
|
||||
private Result<?> initDedicatedLineInfo() {
|
||||
Result<?> result = Result.succ();
|
||||
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_api_pairing_info");
|
||||
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_dedicated_line_info");
|
||||
resources.collectList()
|
||||
.defaultIfEmpty(Collections.emptyList())
|
||||
.flatMap(
|
||||
@@ -74,19 +74,19 @@ public class ApiPairingInfoService {
|
||||
try {
|
||||
for (Map.Entry<Object, Object> e : es) {
|
||||
json = (String) e.getValue();
|
||||
ApiPairingInfo info = JacksonUtils.readValue(json, ApiPairingInfo.class);
|
||||
DedicatedLineInfo info = JacksonUtils.readValue(json, DedicatedLineInfo.class);
|
||||
for (String service : info.services) {
|
||||
serviceApiPairingInfoMap.put(service, info);
|
||||
serviceDedicatedLineInfoMap.put(service, info);
|
||||
}
|
||||
log.info("init api pairing info: {}", info);
|
||||
log.info("init dedicated line info: {}", info);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "init api pairing info error, info: " + json;
|
||||
result.msg = "init dedicated line info error, info: " + json;
|
||||
result.t = t;
|
||||
}
|
||||
} else {
|
||||
log.info("no api pairing info");
|
||||
log.info("no dedicated line info");
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
@@ -94,7 +94,7 @@ public class ApiPairingInfoService {
|
||||
.onErrorReturn(
|
||||
throwable -> {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "init api pairing info error";
|
||||
result.msg = "init dedicated line info error";
|
||||
result.t = throwable;
|
||||
return true;
|
||||
},
|
||||
@@ -106,7 +106,7 @@ public class ApiPairingInfoService {
|
||||
|
||||
private Result<?> lsnApiPairingInfoChange() {
|
||||
Result<?> result = Result.succ();
|
||||
String channel = "fizz_api_pairing_info_channel";
|
||||
String channel = "fizz_dedicated_line_info_channel";
|
||||
rt.listenToChannel(channel)
|
||||
.doOnError(
|
||||
t -> {
|
||||
@@ -125,20 +125,20 @@ public class ApiPairingInfoService {
|
||||
msg -> {
|
||||
String message = msg.getMessage();
|
||||
try {
|
||||
ApiPairingInfo info = JacksonUtils.readValue(message, ApiPairingInfo.class);
|
||||
if (info.isDeleted == ApiPairingDocSet.DELETED) {
|
||||
DedicatedLineInfo info = JacksonUtils.readValue(message, DedicatedLineInfo.class);
|
||||
if (info.isDeleted) {
|
||||
for (String service : info.services) {
|
||||
serviceApiPairingInfoMap.remove(service);
|
||||
serviceDedicatedLineInfoMap.remove(service);
|
||||
}
|
||||
log.info("remove api pairing info: {}", info);
|
||||
log.info("remove dedicated line info: {}", info);
|
||||
} else {
|
||||
for (String service : info.services) {
|
||||
serviceApiPairingInfoMap.put(service, info);
|
||||
serviceDedicatedLineInfoMap.put(service, info);
|
||||
}
|
||||
log.info("update api pairing info: {}", info);
|
||||
log.info("update dedicated line info: {}", info);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.error("update api pairing info error, {}", message, t);
|
||||
log.error("update dedicated line info error, {}", message, t);
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -146,11 +146,7 @@ public class ApiPairingInfoService {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, ApiPairingInfo> getServiceApiPairingInfoMap() {
|
||||
return serviceApiPairingInfoMap;
|
||||
}
|
||||
|
||||
public ApiPairingInfo get(String service) {
|
||||
return serviceApiPairingInfoMap.get(service);
|
||||
public DedicatedLineInfo get(String service) {
|
||||
return serviceDedicatedLineInfoMap.get(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.config.AggregateRedisConfig;
|
||||
import we.config.SystemConfig;
|
||||
import we.plugin.auth.ApiConfig;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.Result;
|
||||
import we.util.UrlTransformUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_SERVER_ENABLE, havingValue = "true")
|
||||
@Service
|
||||
public class DedicatedLineService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineService.class);
|
||||
|
||||
private Map<String, DedicatedLine> dedicatedLineMap = new HashMap<>(32);
|
||||
|
||||
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
|
||||
private ReactiveStringRedisTemplate rt;
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws Throwable {
|
||||
Result<?> result = initDedicatedLine();
|
||||
if (result.code == Result.FAIL) {
|
||||
throw new RuntimeException(result.msg, result.t);
|
||||
}
|
||||
result = lsnDedicatedLineChange();
|
||||
if (result.code == Result.FAIL) {
|
||||
throw new RuntimeException(result.msg, result.t);
|
||||
}
|
||||
}
|
||||
|
||||
private Result<?> initDedicatedLine() {
|
||||
Result<?> result = Result.succ();
|
||||
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_dedicated_line");
|
||||
resources.collectList()
|
||||
.defaultIfEmpty(Collections.emptyList())
|
||||
.flatMap(
|
||||
es -> {
|
||||
if (!es.isEmpty()) {
|
||||
String json = null;
|
||||
try {
|
||||
for (Map.Entry<Object, Object> e : es) {
|
||||
json = (String) e.getValue();
|
||||
DedicatedLine dl = JacksonUtils.readValue(json, DedicatedLine.class);
|
||||
dedicatedLineMap.put(dl.pairCodeId, dl);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "init dedicated line error, json: " + json;
|
||||
result.t = t;
|
||||
}
|
||||
} else {
|
||||
log.info("no dedicated line");
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
)
|
||||
.onErrorReturn(
|
||||
throwable -> {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "init dedicated line error";
|
||||
result.t = throwable;
|
||||
return true;
|
||||
},
|
||||
result
|
||||
)
|
||||
.block();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Result<?> lsnDedicatedLineChange() {
|
||||
Result<?> result = Result.succ();
|
||||
String channel = "fizz_dedicated_line_channel";
|
||||
rt.listenToChannel(channel)
|
||||
.doOnError(
|
||||
t -> {
|
||||
result.code = Result.FAIL;
|
||||
result.msg = "lsn error, channel: " + channel;
|
||||
result.t = t;
|
||||
log.error("lsn channel {} error", channel, t);
|
||||
}
|
||||
)
|
||||
.doOnSubscribe(
|
||||
s -> {
|
||||
log.info("success to lsn on {}", channel);
|
||||
}
|
||||
)
|
||||
.doOnNext(
|
||||
msg -> {
|
||||
String message = msg.getMessage();
|
||||
try {
|
||||
DedicatedLine dl = JacksonUtils.readValue(message, DedicatedLine.class);
|
||||
if (dl.isDeleted) {
|
||||
dedicatedLineMap.remove(dl.pairCodeId);
|
||||
} else {
|
||||
dedicatedLineMap.put(dl.pairCodeId, dl);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.error("update dedicated line error, {}", message, t);
|
||||
}
|
||||
}
|
||||
)
|
||||
.subscribe();
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean auth(String pairCodeId, HttpMethod method, String service, String path) {
|
||||
DedicatedLine dedicatedLine = dedicatedLineMap.get(pairCodeId);
|
||||
if (dedicatedLine == null) {
|
||||
return false;
|
||||
}
|
||||
if (dedicatedLine.servicesWithoutApiDocs.contains(service)) {
|
||||
return true;
|
||||
}
|
||||
Map<Object, Set<String>> methodPathsMap = dedicatedLine.apiDocMap.get(service);
|
||||
if (methodPathsMap == null) {
|
||||
return false;
|
||||
}
|
||||
Set<String> pathPatterns = methodPathsMap.get(method);
|
||||
if (pathPatterns != null) {
|
||||
if (pathPatternMatch(path, pathPatterns)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
pathPatterns = methodPathsMap.get(ApiConfig.ALL_METHOD);
|
||||
if (pathPatterns != null) {
|
||||
return pathPatternMatch(path, pathPatterns);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean pathPatternMatch(String path, Set<String> pathPatterns) {
|
||||
if (pathPatterns.contains(path)) {
|
||||
return true;
|
||||
}
|
||||
for (String pathPattern : pathPatterns) {
|
||||
if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPairCodeSecretKey(String pairCodeId) {
|
||||
DedicatedLine dedicatedLine = dedicatedLineMap.get(pairCodeId);
|
||||
if (dedicatedLine != null) {
|
||||
return dedicatedLine.secretKey;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -47,9 +47,9 @@ import javax.annotation.PreDestroy;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnDiscoveryEnabled
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_CLIENT_ENABLE, havingValue = "true")
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_ENABLE, havingValue = "true")
|
||||
@AutoConfigureAfter({EurekaClientAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class})
|
||||
public class ApiPairingServiceRegistration implements ApplicationListener<FizzApiPairingWebServerInitializedEvent> {
|
||||
public class DedicatedLineServiceRegistration implements ApplicationListener<DedicatedLineWebServerInitializedEvent> {
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
@@ -57,12 +57,12 @@ public class ApiPairingServiceRegistration implements ApplicationListener<FizzAp
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void onApplicationEvent(FizzApiPairingWebServerInitializedEvent event) {
|
||||
public void onApplicationEvent(DedicatedLineWebServerInitializedEvent event) {
|
||||
|
||||
ReactiveWebServerApplicationContext applicationContext = event.getApplicationContext();
|
||||
ConfigurableEnvironment env = applicationContext.getEnvironment();
|
||||
|
||||
String prefix = SystemConfig.FIZZ_API_PAIRING_CLIENT_PREFIX + ".service-registration";
|
||||
String prefix = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_PREFIX + ".service-registration";
|
||||
String type = env.getProperty(prefix + ".type");
|
||||
|
||||
if (StringUtils.isNotBlank(type)) {
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import we.util.Consts;
|
||||
import we.util.ThreadContext;
|
||||
@@ -24,29 +24,29 @@ import we.util.ThreadContext;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public abstract class ApiPairingUtils extends org.apache.commons.codec.digest.DigestUtils {
|
||||
public abstract class DedicatedLineUtils extends org.apache.commons.codec.digest.DigestUtils {
|
||||
|
||||
private ApiPairingUtils() {
|
||||
private DedicatedLineUtils() {
|
||||
}
|
||||
|
||||
public static String sign(String app, String timestamp, String secretKey) {
|
||||
public static String sign(String pairCodeId, String timestamp, String secretKey) {
|
||||
StringBuilder b = ThreadContext.getStringBuilder(ThreadContext.sb0);
|
||||
b.append(app) .append(Consts.S.UNDER_LINE)
|
||||
.append(timestamp).append(Consts.S.UNDER_LINE)
|
||||
b.append(pairCodeId).append(Consts.S.UNDER_LINE)
|
||||
.append(timestamp) .append(Consts.S.UNDER_LINE)
|
||||
.append(secretKey);
|
||||
return sha256Hex(b.toString());
|
||||
}
|
||||
|
||||
public static String sign(String app, long timestamp, String secretKey) {
|
||||
return sign(app, String.valueOf(timestamp), secretKey);
|
||||
public static String sign(String pairCodeId, long timestamp, String secretKey) {
|
||||
return sign(pairCodeId, String.valueOf(timestamp), secretKey);
|
||||
}
|
||||
|
||||
public static boolean checkSign(String app, String timestamp, String secretKey, String sign) {
|
||||
String s = sign(app, timestamp, secretKey);
|
||||
public static boolean checkSign(String pairCodeId, String timestamp, String secretKey, String sign) {
|
||||
String s = sign(pairCodeId, timestamp, secretKey);
|
||||
return s.equals(sign);
|
||||
}
|
||||
|
||||
public static boolean checkSign(String app, long timestamp, String secretKey, String sign) {
|
||||
return checkSign(app, String.valueOf(timestamp), secretKey, sign);
|
||||
public static boolean checkSign(String pairCodeId, long timestamp, String secretKey, String sign) {
|
||||
return checkSign(pairCodeId, String.valueOf(timestamp), secretKey, sign);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -40,12 +40,12 @@ import javax.annotation.Resource;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_CLIENT_ENABLE, havingValue = "true")
|
||||
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_ENABLE, havingValue = "true")
|
||||
@Configuration
|
||||
@AutoConfigureAfter({HttpHandlerAutoConfiguration.class})
|
||||
public class FizzApiPairingWebServer {
|
||||
public class DedicatedLineWebServer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FizzApiPairingWebServer.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineWebServer.class);
|
||||
|
||||
@Resource
|
||||
private ReactiveWebServerApplicationContext applicationContext;
|
||||
@@ -55,7 +55,7 @@ public class FizzApiPairingWebServer {
|
||||
|
||||
private WebServer server;
|
||||
|
||||
@Value("${fizz.api.pairing.client.port:8601}")
|
||||
@Value("${fizz.dedicated-line.client.port:8601}")
|
||||
private int port = 8601;
|
||||
|
||||
@PostConstruct
|
||||
@@ -63,7 +63,7 @@ public class FizzApiPairingWebServer {
|
||||
HttpWebHandlerAdapter adapter = (HttpWebHandlerAdapter) httpHandler;
|
||||
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory(port);
|
||||
server = factory.getWebServer(
|
||||
new FizzApiPairingHttpHandler(
|
||||
new DedicatedLineHttpHandler(
|
||||
applicationContext,
|
||||
new DefaultWebSessionManager(),
|
||||
adapter.getCodecConfigurer(),
|
||||
@@ -72,8 +72,8 @@ public class FizzApiPairingWebServer {
|
||||
)
|
||||
);
|
||||
server.start();
|
||||
log.info("fizz api pairing web server listen on {}", port);
|
||||
applicationContext.publishEvent(new FizzApiPairingWebServerInitializedEvent(server, applicationContext));
|
||||
log.info("fizz dedicated line web server listen on {}", port);
|
||||
applicationContext.publishEvent(new DedicatedLineWebServerInitializedEvent(server, applicationContext));
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
@@ -25,11 +25,11 @@ import org.springframework.context.ApplicationEvent;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class FizzApiPairingWebServerInitializedEvent extends ApplicationEvent {
|
||||
public class DedicatedLineWebServerInitializedEvent extends ApplicationEvent {
|
||||
|
||||
private final ReactiveWebServerApplicationContext applicationContext;
|
||||
|
||||
public FizzApiPairingWebServerInitializedEvent(WebServer webServer, ReactiveWebServerApplicationContext applicationContext) {
|
||||
public DedicatedLineWebServerInitializedEvent(WebServer webServer, ReactiveWebServerApplicationContext applicationContext) {
|
||||
super(webServer);
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.api.pairing;
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import we.plugin.auth.ApiConfig;
|
||||
@@ -25,7 +25,7 @@ import we.util.JacksonUtils;
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
public class Api {
|
||||
public class MethodAndPath {
|
||||
|
||||
public Object method;
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -38,7 +37,9 @@ import we.exception.StopAndResponseException;
|
||||
import we.fizz.exception.FizzRuntimeException;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.legacy.RespEntity;
|
||||
import we.util.*;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.ThreadContext;
|
||||
import we.util.WebUtils;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@@ -92,7 +93,7 @@ public class FilterExceptionHandlerConfig {
|
||||
RespEntity rs = null;
|
||||
if (ex.getStepContext() != null && ex.getStepContext().returnContext()) {
|
||||
rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), tMsg, traceId, ex.getStepContext());
|
||||
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes())));
|
||||
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsBytes(rs))));
|
||||
} else {
|
||||
rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), tMsg, traceId);
|
||||
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes())));
|
||||
|
||||
@@ -31,7 +31,7 @@ public abstract class FizzWebFilter implements WebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
if (WebUtils.isAdminReq(exchange) || WebUtils.isFizzApiReq(exchange)) {
|
||||
if (WebUtils.isAdminReq(exchange) || WebUtils.isFizzReq(exchange)) {
|
||||
return chain.filter(exchange);
|
||||
} else {
|
||||
return doFilter(exchange, chain);
|
||||
|
||||
@@ -32,7 +32,6 @@ import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.SignalType;
|
||||
import we.config.SystemConfig;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.legacy.RespEntity;
|
||||
import we.plugin.auth.ApiConfigService;
|
||||
import we.plugin.auth.AppService;
|
||||
import we.stats.BlockType;
|
||||
@@ -71,7 +70,7 @@ public class FlowControlFilter extends FizzWebFilter {
|
||||
|
||||
|
||||
@Resource
|
||||
private FlowControlFilterProperties flowControlFilterProperties;
|
||||
private FlowControlFilterProperties flowControlFilterProperties;
|
||||
|
||||
@Resource
|
||||
private ResourceRateLimitConfigService resourceRateLimitConfigService;
|
||||
@@ -83,10 +82,10 @@ public class FlowControlFilter extends FizzWebFilter {
|
||||
private ApiConfigService apiConfigService;
|
||||
|
||||
@Resource
|
||||
private AppService appService;
|
||||
private AppService appService;
|
||||
|
||||
@Resource
|
||||
private SystemConfig systemConfig;
|
||||
private SystemConfig systemConfig;
|
||||
|
||||
@Override
|
||||
public Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
@@ -107,7 +106,7 @@ public class FlowControlFilter extends FizzWebFilter {
|
||||
service = WebUtils.getClientService(exchange);
|
||||
if (service.startsWith(_fizz)) {
|
||||
fizzApiReq = true;
|
||||
exchange.getAttributes().put(WebUtils.FIZZ_API_REQUEST, Consts.S.EMPTY);
|
||||
exchange.getAttributes().put(WebUtils.FIZZ_REQUEST, Consts.S.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,7 @@ public class GlobalResource {
|
||||
public static final int NUMBER = 3;
|
||||
public static final int JSON = 4;
|
||||
|
||||
public static final int DELETED = 1;
|
||||
|
||||
public int isDeleted = 0;
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public int id;
|
||||
|
||||
@@ -86,7 +84,9 @@ public class GlobalResource {
|
||||
@JsonProperty("update") long update
|
||||
) {
|
||||
|
||||
this.isDeleted = isDeleted;
|
||||
if (isDeleted == 1) {
|
||||
this.isDeleted = true;
|
||||
}
|
||||
this.id = id;
|
||||
this.key = key;
|
||||
this.type = type;
|
||||
|
||||
@@ -134,7 +134,7 @@ public class GlobalResourceService {
|
||||
String message = msg.getMessage();
|
||||
try {
|
||||
GlobalResource r = JacksonUtils.readValue(message, GlobalResource.class);
|
||||
if (r.isDeleted == GlobalResource.DELETED) {
|
||||
if (r.isDeleted) {
|
||||
resourceMap.remove(r.key);
|
||||
objectMap.remove(r.key);
|
||||
log.info("remove global resource {}", r.key);
|
||||
|
||||
@@ -27,7 +27,6 @@ import we.plugin.PluginConfig;
|
||||
import we.proxy.Route;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.UrlTransformUtils;
|
||||
import we.util.WebUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
@@ -49,15 +48,9 @@ public class ApiConfig {
|
||||
static final byte DUBBO = 5;
|
||||
}
|
||||
|
||||
public static final int DELETED = 1;
|
||||
public static final String ALL_METHOD = "AM";
|
||||
|
||||
public static final char ALLOW = 'a';
|
||||
|
||||
public static final String ALL_METHOD = "AM";
|
||||
|
||||
private static final String match_all = "/**";
|
||||
|
||||
private static final int ENABLE = 1;
|
||||
private static final String match_all = "/**";
|
||||
|
||||
@JsonProperty(
|
||||
access = JsonProperty.Access.WRITE_ONLY
|
||||
@@ -67,7 +60,7 @@ public class ApiConfig {
|
||||
@JsonProperty(
|
||||
access = JsonProperty.Access.WRITE_ONLY
|
||||
)
|
||||
public int isDeleted = 0;
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public Set<String> gatewayGroups = Stream.of(GatewayGroup.DEFAULT).collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
@@ -80,11 +73,6 @@ public class ApiConfig {
|
||||
|
||||
public String backendService;
|
||||
|
||||
@JsonProperty(
|
||||
access = JsonProperty.Access.WRITE_ONLY
|
||||
)
|
||||
public HttpMethod method;
|
||||
|
||||
public Object fizzMethod = ALL_METHOD;
|
||||
|
||||
public String path = match_all;
|
||||
@@ -96,6 +84,8 @@ public class ApiConfig {
|
||||
|
||||
public String backendPath;
|
||||
|
||||
public boolean dedicatedLine = false;
|
||||
|
||||
@JsonProperty("proxyMode")
|
||||
public byte type = Type.SERVICE_DISCOVERY;
|
||||
|
||||
@@ -103,7 +93,7 @@ public class ApiConfig {
|
||||
|
||||
public List<String> httpHostPorts;
|
||||
|
||||
public char access = ALLOW;
|
||||
public boolean allowAccess = true;
|
||||
|
||||
public List<PluginConfig> pluginConfigs = Collections.emptyList();
|
||||
|
||||
@@ -125,6 +115,18 @@ public class ApiConfig {
|
||||
|
||||
public long retryInterval = 0;
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAccess(char c) {
|
||||
if (c != 'a') {
|
||||
allowAccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setGatewayGroup(String ggs) {
|
||||
gatewayGroups.remove(GatewayGroup.DEFAULT);
|
||||
if (StringUtils.isBlank(ggs)) {
|
||||
@@ -155,19 +157,21 @@ public class ApiConfig {
|
||||
}
|
||||
|
||||
public void setMethod(String m) {
|
||||
method = HttpMethod.resolve(m);
|
||||
if (method == null) {
|
||||
fizzMethod = HttpMethod.resolve(m);
|
||||
if (fizzMethod == null) {
|
||||
fizzMethod = ALL_METHOD;
|
||||
} else {
|
||||
fizzMethod = method;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAppEnable(int v) {
|
||||
if (v == ENABLE) {
|
||||
if (v == 1) {
|
||||
checkApp = true;
|
||||
} else {
|
||||
checkApp = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDedicatedLine(int v) {
|
||||
if (v == 1) {
|
||||
dedicatedLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +209,8 @@ public class ApiConfig {
|
||||
|
||||
public Route getRoute(ServerWebExchange exchange, @Nullable List<PluginConfig> gatewayGroupPluginConfigs) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Route r = new Route().type( this.type)
|
||||
Route r = new Route().dedicatedLine( this.dedicatedLine)
|
||||
.type( this.type)
|
||||
.method( request.getMethod())
|
||||
.backendService(this.backendService)
|
||||
.backendPath( this.backendPath)
|
||||
|
||||
@@ -27,14 +27,18 @@ import java.util.List;
|
||||
|
||||
public class ApiConfig2apps {
|
||||
|
||||
public static final int DELETED = 1;
|
||||
|
||||
public int id;
|
||||
|
||||
public int isDeleted = 0;
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public List<String> apps;
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JacksonUtils.writeValueAsString(this);
|
||||
|
||||
@@ -38,9 +38,9 @@ import java.util.*;
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class ApiConifg2appsService {
|
||||
public class ApiConfig2appsService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiConifg2appsService.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiConfig2appsService.class);
|
||||
|
||||
private static final String fizzApiConfigAppSetSize = "fizz_api_config_app_set_size";
|
||||
|
||||
@@ -120,11 +120,7 @@ public class ApiConifg2appsService {
|
||||
}
|
||||
|
||||
private void save(Integer apiConfigId, List<String> as, Map<Integer, Set<String>> apiConfig2appsMap) {
|
||||
Set<String> appSet = apiConfig2appsMap.get(apiConfigId);
|
||||
if (appSet == null) {
|
||||
appSet = new HashSet<>();
|
||||
apiConfig2appsMap.put(apiConfigId, appSet);
|
||||
}
|
||||
Set<String> appSet = apiConfig2appsMap.computeIfAbsent(apiConfigId, k -> new HashSet<>());
|
||||
appSet.addAll(as);
|
||||
log(apiConfigId, as);
|
||||
}
|
||||
@@ -168,9 +164,9 @@ public class ApiConifg2appsService {
|
||||
|
||||
private void updateApiConfig2appsMap(ApiConfig2apps data) {
|
||||
Set<String> apps = apiConfig2appsMap.get(data.id);
|
||||
if (data.isDeleted == ApiConfig2apps.DELETED) {
|
||||
if (data.isDeleted) {
|
||||
if (apps != null) {
|
||||
apps.removeAll(data.apps);
|
||||
data.apps.forEach(apps::remove);
|
||||
log.info("remove " + data);
|
||||
}
|
||||
} else {
|
||||
@@ -25,7 +25,6 @@ import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicatio
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
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;
|
||||
@@ -54,7 +53,7 @@ import java.util.regex.Pattern;
|
||||
@Service
|
||||
public class ApiConfigService implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiConfigService.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiConfigService.class);
|
||||
|
||||
public Map<String, ServiceConfig> serviceConfigMap = new HashMap<>(128);
|
||||
|
||||
@@ -75,7 +74,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
private AppService appService;
|
||||
|
||||
@Resource
|
||||
private ApiConifg2appsService apiConifg2appsService;
|
||||
private ApiConfig2appsService apiConfig2AppsService;
|
||||
|
||||
@Resource
|
||||
private GatewayGroupService gatewayGroupService;
|
||||
@@ -110,9 +109,8 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
if (k == ReactorUtils.OBJ) {
|
||||
return Flux.just(e);
|
||||
}
|
||||
Object v = e.getValue();
|
||||
log.info("init api config: {}", v.toString(), LogService.BIZ_ID, k.toString());
|
||||
String json = (String) v;
|
||||
String json = (String) e.getValue();
|
||||
log.info("init api config: {}", json, LogService.BIZ_ID, k.toString());
|
||||
try {
|
||||
ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class);
|
||||
apiConfigMapTmp.put(ac.id, ac);
|
||||
@@ -162,15 +160,15 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
try {
|
||||
ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class);
|
||||
ApiConfig r = apiConfigMap.remove(ac.id);
|
||||
if (ac.isDeleted != ApiConfig.DELETED && r != null) {
|
||||
r.isDeleted = ApiConfig.DELETED;
|
||||
if (!ac.isDeleted && r != null) {
|
||||
r.isDeleted = true;
|
||||
updateServiceConfigMap(r, serviceConfigMap);
|
||||
}
|
||||
updateServiceConfigMap(ac, serviceConfigMap);
|
||||
if (ac.isDeleted != ApiConfig.DELETED) {
|
||||
if (!ac.isDeleted) {
|
||||
apiConfigMap.put(ac.id, ac);
|
||||
} else {
|
||||
apiConifg2appsService.remove(ac.id);
|
||||
apiConfig2AppsService.remove(ac.id);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.error("deser {}", json, t);
|
||||
@@ -289,7 +287,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
|
||||
public void updateServiceConfigMap(ApiConfig ac, Map<String, ServiceConfig> serviceConfigMap) {
|
||||
ServiceConfig sc = serviceConfigMap.get(ac.service);
|
||||
if (ac.isDeleted == ApiConfig.DELETED) {
|
||||
if (ac.isDeleted) {
|
||||
if (sc != null) {
|
||||
sc.remove(ac);
|
||||
if (sc.apiConfigMap.isEmpty()) {
|
||||
@@ -353,26 +351,26 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
}
|
||||
|
||||
public ApiConfig getApiConfig(String app, String service, HttpMethod method, String path) {
|
||||
Result<ApiConfig> result = get(null, app, service, method, path);
|
||||
Result<ApiConfig> result = get(false, null, app, service, method, path);
|
||||
if (result.code == Result.SUCC) {
|
||||
return result.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Result<ApiConfig> get(String app, String service, HttpMethod method, String path) {
|
||||
return get(null, app, service, method, path);
|
||||
public Result<ApiConfig> get(boolean dedicatedLineRequest, String app, String service, HttpMethod method, String path) {
|
||||
return get(dedicatedLineRequest, null, app, service, method, path);
|
||||
}
|
||||
|
||||
public ApiConfig getApiConfig(Set<String> gatewayGroups, String app, String service, HttpMethod method, String path) {
|
||||
Result<ApiConfig> result = get(null, app, service, method, path);
|
||||
Result<ApiConfig> result = get(false, null, app, service, method, path);
|
||||
if (result.code == Result.SUCC) {
|
||||
return result.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Result<ApiConfig> get(Set<String> gatewayGroups, String app, String service, HttpMethod method, String path) {
|
||||
public Result<ApiConfig> get(boolean dedicatedLineRequest, Set<String> gatewayGroups, String app, String service, HttpMethod method, String path) {
|
||||
ServiceConfig sc = serviceConfigMap.get(service);
|
||||
if (sc == null) {
|
||||
return Result.fail("no " + service + " service api config");
|
||||
@@ -380,34 +378,34 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
if (CollectionUtils.isEmpty(gatewayGroups)) {
|
||||
gatewayGroups = gatewayGroupService.currentGatewayGroupSet;
|
||||
}
|
||||
List<ApiConfig> apiConfigs = sc.getApiConfigs(gatewayGroups, method, path);
|
||||
List<ApiConfig> apiConfigs = sc.getApiConfigs(dedicatedLineRequest, gatewayGroups, method, path);
|
||||
if (apiConfigs.isEmpty()) {
|
||||
StringBuilder b = ThreadContext.getStringBuilder();
|
||||
b.append(service).append(" don't have api config matching ").append(gatewayGroups).append(" group ").append(method).append(" method ").append(path).append(" path");
|
||||
return Result.fail(b.toString());
|
||||
}
|
||||
List<ApiConfig> appCanAccess = ThreadContext.getArrayList();
|
||||
List<ApiConfig> clientCanAccess = ThreadContext.getArrayList();
|
||||
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 (!dedicatedLineRequest && ac.checkApp) {
|
||||
if (StringUtils.isNotBlank(app) && apiConfig2AppsService.contains(ac.id, app)) {
|
||||
clientCanAccess.add(ac);
|
||||
}
|
||||
} else {
|
||||
appCanAccess.add(ac);
|
||||
clientCanAccess.add(ac);
|
||||
}
|
||||
}
|
||||
if (appCanAccess.isEmpty()) {
|
||||
if (clientCanAccess.isEmpty()) {
|
||||
StringBuilder b = ThreadContext.getStringBuilder();
|
||||
b.append("app ").append(app).append(" can't access ").append(JacksonUtils.writeValueAsString(apiConfigs));
|
||||
return Result.fail(b.toString());
|
||||
}
|
||||
ApiConfig bestOne = appCanAccess.get(0);
|
||||
if (appCanAccess.size() != 1) {
|
||||
appCanAccess.sort(new ApiConfigPathPatternComparator(path)); // singleton ?
|
||||
ApiConfig ac0 = appCanAccess.get(0);
|
||||
ApiConfig bestOne = clientCanAccess.get(0);
|
||||
if (clientCanAccess.size() != 1) {
|
||||
clientCanAccess.sort(new ApiConfigPathPatternComparator(path)); // singleton ?
|
||||
ApiConfig ac0 = clientCanAccess.get(0);
|
||||
bestOne = ac0;
|
||||
ApiConfig ac1 = appCanAccess.get(1);
|
||||
ApiConfig ac1 = clientCanAccess.get(1);
|
||||
if (ac0.path.equals(ac1.path)) {
|
||||
if (ac0.fizzMethod == ac1.fizzMethod) {
|
||||
if (StringUtils.isNotBlank(app)) {
|
||||
@@ -428,11 +426,14 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
public Mono<Result<ApiConfig>> auth(ServerWebExchange exchange) {
|
||||
ServerHttpRequest req = exchange.getRequest();
|
||||
LogService.setBizId(WebUtils.getTraceId(exchange));
|
||||
return auth(exchange, WebUtils.getAppId(exchange), WebUtils.getOriginIp(exchange), WebUtils.getTimestamp(exchange), WebUtils.getSign(exchange),
|
||||
WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange));
|
||||
boolean dedicatedLineRequest = WebUtils.isDedicatedLineRequest(exchange);
|
||||
return auth(exchange, dedicatedLineRequest,
|
||||
WebUtils.getAppId(exchange), WebUtils.getOriginIp(exchange), WebUtils.getTimestamp(exchange), WebUtils.getSign(exchange),
|
||||
WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange));
|
||||
}
|
||||
|
||||
private Mono<Result<ApiConfig>> auth(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String service, HttpMethod method, String path) {
|
||||
private Mono<Result<ApiConfig>> auth(ServerWebExchange exchange, boolean dedicatedLineRequest,
|
||||
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))) {
|
||||
@@ -440,7 +441,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
}
|
||||
}
|
||||
|
||||
Result<ApiConfig> r = get(app, service, method, path);
|
||||
Result<ApiConfig> r = get(dedicatedLineRequest, app, service, method, path);
|
||||
if (r.code == Result.FAIL) {
|
||||
if (apiConfigServiceProperties.isNeedAuth()) {
|
||||
return Mono.just(r);
|
||||
@@ -450,7 +451,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
}
|
||||
|
||||
ApiConfig ac = r.data;
|
||||
if (ac.checkApp) {
|
||||
if (!dedicatedLineRequest && ac.checkApp) {
|
||||
App a = appService.getApp(app);
|
||||
if (a.useWhiteList && !a.allow(ip)) {
|
||||
r.code = Result.FAIL;
|
||||
@@ -487,7 +488,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
|
||||
return Mono.just(r);
|
||||
} else {
|
||||
r.code = Result.FAIL;
|
||||
r.msg = v.getReason();
|
||||
r.msg = v.getReason();
|
||||
return Mono.just(r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package we.plugin.auth;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import we.util.Consts;
|
||||
import we.util.JacksonUtils;
|
||||
|
||||
@@ -30,9 +29,7 @@ import java.util.*;
|
||||
|
||||
public class App {
|
||||
|
||||
public static final String ALL_APP = "*";
|
||||
|
||||
public static final int DELETED = 1;
|
||||
public static final String ALL_APP = "*";
|
||||
|
||||
static interface AUTH_TYPE {
|
||||
static final int SIGN = 1;
|
||||
@@ -40,7 +37,7 @@ public class App {
|
||||
static final int SECRET_KEY = 3;
|
||||
}
|
||||
|
||||
public int isDeleted = 0; // tb_app_auth.is_deleted
|
||||
public boolean isDeleted = false; // tb_app_auth.is_deleted
|
||||
|
||||
public int id; // tb_app_auth.id
|
||||
|
||||
@@ -60,6 +57,12 @@ public class App {
|
||||
|
||||
public Map<String, List<String[]>> ips = new HashMap<>();
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseAuth(int i) {
|
||||
if (i == AUTH_TYPE.SIGN || i == AUTH_TYPE.SECRET_KEY || i == AUTH_TYPE.CUSTOM) {
|
||||
useAuth = true;
|
||||
|
||||
@@ -23,9 +23,8 @@ import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.config.AggregateRedisConfig;
|
||||
import we.util.Consts;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.ReactorUtils;
|
||||
|
||||
@@ -80,9 +79,8 @@ public class AppService {
|
||||
if (k == ReactorUtils.OBJ) {
|
||||
return Flux.just(e);
|
||||
}
|
||||
Object v = e.getValue();
|
||||
log.info("init app: {}", v.toString(), LogService.BIZ_ID, k.toString());
|
||||
String json = (String) v;
|
||||
String json = (String) e.getValue();
|
||||
log.info("init app: {}", json, LogService.BIZ_ID, k.toString());
|
||||
try {
|
||||
App app = JacksonUtils.readValue(json, App.class);
|
||||
oldAppMapTmp.put(app.id, app);
|
||||
@@ -127,15 +125,15 @@ public class AppService {
|
||||
}
|
||||
).doOnNext(msg -> {
|
||||
String json = msg.getMessage();
|
||||
log.info(json, LogService.BIZ_ID, "ac" + System.currentTimeMillis());
|
||||
log.info("app change: " + json, LogService.BIZ_ID, "ac" + System.currentTimeMillis());
|
||||
try {
|
||||
App app = JacksonUtils.readValue(json, App.class);
|
||||
App r = oldAppMap.remove(app.id);
|
||||
if (app.isDeleted != App.DELETED && r != null) {
|
||||
if (!app.isDeleted && r != null) {
|
||||
appMap.remove(r.app);
|
||||
}
|
||||
updateAppMap(app, appMap);
|
||||
if (app.isDeleted != App.DELETED) {
|
||||
if (!app.isDeleted) {
|
||||
oldAppMap.put(app.id, app);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
@@ -158,7 +156,7 @@ public class AppService {
|
||||
}
|
||||
|
||||
private void updateAppMap(App app, Map<String, App> appMap) {
|
||||
if (app.isDeleted == App.DELETED) {
|
||||
if (app.isDeleted) {
|
||||
App removedApp = appMap.remove(app.app);
|
||||
log.info("remove " + removedApp);
|
||||
} else {
|
||||
|
||||
@@ -35,11 +35,9 @@ public class GatewayGroup {
|
||||
|
||||
public static final String DEFAULT = "default";
|
||||
|
||||
public static final int DELETED = 1;
|
||||
|
||||
public int id;
|
||||
|
||||
public int isDeleted = 0;
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public String group;
|
||||
|
||||
@@ -49,6 +47,12 @@ public class GatewayGroup {
|
||||
|
||||
public List<PluginConfig> pluginConfigs = Collections.emptyList();
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setGateways(String gateways) {
|
||||
if (StringUtils.isNotBlank(gateways)) {
|
||||
Arrays.stream(StringUtils.split(gateways, ',')).forEach(
|
||||
|
||||
@@ -26,7 +26,6 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.config.AggregateRedisConfig;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.util.Consts;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.NetworkUtils;
|
||||
import we.util.ReactorUtils;
|
||||
@@ -87,9 +86,8 @@ public class GatewayGroupService {
|
||||
if (k == ReactorUtils.OBJ) {
|
||||
return Flux.just(e);
|
||||
}
|
||||
Object v = e.getValue();
|
||||
log.info(k.toString() + Consts.S.COLON + v.toString(), LogService.BIZ_ID, k.toString());
|
||||
String json = (String) v;
|
||||
String json = (String) e.getValue();
|
||||
log.info(json, LogService.BIZ_ID, k.toString());
|
||||
try {
|
||||
GatewayGroup gg = JacksonUtils.readValue(json, GatewayGroup.class);
|
||||
oldGatewayGroupMapTmp.put(gg.id, gg);
|
||||
@@ -139,11 +137,11 @@ public class GatewayGroupService {
|
||||
try {
|
||||
GatewayGroup gg = JacksonUtils.readValue(json, GatewayGroup.class);
|
||||
GatewayGroup r = oldGatewayGroupMap.remove(gg.id);
|
||||
if (gg.isDeleted != GatewayGroup.DELETED && r != null) {
|
||||
if (!gg.isDeleted && r != null) {
|
||||
gatewayGroupMap.remove(r.group);
|
||||
}
|
||||
updateGatewayGroupMap(gg, gatewayGroupMap, currentGatewayGroupSet);
|
||||
if (gg.isDeleted != GatewayGroup.DELETED) {
|
||||
if (!gg.isDeleted) {
|
||||
oldGatewayGroupMap.put(gg.id, gg);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
@@ -166,7 +164,7 @@ public class GatewayGroupService {
|
||||
}
|
||||
|
||||
private void updateGatewayGroupMap(GatewayGroup gg, Map<String, GatewayGroup> gatewayGroupMap, Set<String> currentGatewayGroupSet) {
|
||||
if (gg.isDeleted == GatewayGroup.DELETED) {
|
||||
if (gg.isDeleted) {
|
||||
GatewayGroup r = gatewayGroupMap.remove(gg.group);
|
||||
log.info("remove " + r);
|
||||
} else {
|
||||
|
||||
@@ -94,17 +94,17 @@ public class ServiceConfig {
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public List<ApiConfig> getApiConfigs(Set<String> gatewayGroups, HttpMethod method, String path) {
|
||||
public List<ApiConfig> getApiConfigs(boolean dedicatedLineRequest, Set<String> gatewayGroups, HttpMethod method, String path) {
|
||||
ArrayList<ApiConfig> result = ThreadContext.getArrayList(ThreadContext.arrayList0);
|
||||
for (String gatewayGroup : gatewayGroups) {
|
||||
List<ApiConfig> apiConfigs = getApiConfigs(gatewayGroup, method, path);
|
||||
List<ApiConfig> apiConfigs = getApiConfigs(dedicatedLineRequest, gatewayGroup, method, path);
|
||||
result.addAll(apiConfigs);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public List<ApiConfig> getApiConfigs(String gatewayGroup, HttpMethod method, String path) {
|
||||
public List<ApiConfig> getApiConfigs(boolean dedicatedLineRequest, String gatewayGroup, HttpMethod method, String path) {
|
||||
Map<Object, Map<String, Set<ApiConfig>>> method2pathPattenMap = apiConfigMap.get(gatewayGroup);
|
||||
if (method2pathPattenMap == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -112,42 +112,50 @@ public class ServiceConfig {
|
||||
ArrayList<ApiConfig> result = ThreadContext.getArrayList();
|
||||
Map<String, Set<ApiConfig>> pathPattern2apiConfigsMap = method2pathPattenMap.get(method);
|
||||
if (pathPattern2apiConfigsMap != null) {
|
||||
checkPathPattern(pathPattern2apiConfigsMap, path, result);
|
||||
checkPathPattern(pathPattern2apiConfigsMap, dedicatedLineRequest, path, result);
|
||||
}
|
||||
pathPattern2apiConfigsMap = method2pathPattenMap.get(ApiConfig.ALL_METHOD);
|
||||
if (pathPattern2apiConfigsMap != null) {
|
||||
checkPathPattern(pathPattern2apiConfigsMap, path, result);
|
||||
checkPathPattern(pathPattern2apiConfigsMap, dedicatedLineRequest, path, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPathPattern(Map<String, Set<ApiConfig>> pathPattern2apiConfigMap, String path, ArrayList<ApiConfig> result) {
|
||||
Set<Map.Entry<String, Set<ApiConfig>>> entries = pathPattern2apiConfigMap.entrySet();
|
||||
boolean clear = false;
|
||||
for (Map.Entry<String, Set<ApiConfig>> entry : entries) {
|
||||
String pathPattern = entry.getKey();
|
||||
Set<ApiConfig> apiConfigs = entry.getValue();
|
||||
if (pathPattern.equals(path)) {
|
||||
for (ApiConfig ac : apiConfigs) {
|
||||
if (ac.access == ApiConfig.ALLOW) {
|
||||
if (!clear && !result.isEmpty()) {
|
||||
result.clear();
|
||||
clear = true;
|
||||
private void checkPathPattern(Map<String, Set<ApiConfig>> pathPattern2apiConfigMap, boolean dedicatedLineRequest, String path, ArrayList<ApiConfig> result) {
|
||||
Set<Map.Entry<String, Set<ApiConfig>>> entries = pathPattern2apiConfigMap.entrySet();
|
||||
boolean clear = false;
|
||||
for (Map.Entry<String, Set<ApiConfig>> entry : entries) {
|
||||
String pathPattern = entry.getKey();
|
||||
Set<ApiConfig> apiConfigs = entry.getValue();
|
||||
if (pathPattern.equals(path)) {
|
||||
for (ApiConfig ac : apiConfigs) {
|
||||
if (ac.allowAccess) {
|
||||
if (!clear && !result.isEmpty()) {
|
||||
result.clear();
|
||||
clear = true;
|
||||
}
|
||||
result.add(ac);
|
||||
}
|
||||
}
|
||||
if (clear && !result.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
} else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
|
||||
for (ApiConfig ac : apiConfigs) {
|
||||
if (ac.allowAccess) {
|
||||
if (dedicatedLineRequest) {
|
||||
if (ac.dedicatedLine) {
|
||||
result.add(ac);
|
||||
}
|
||||
} else {
|
||||
if (!ac.dedicatedLine) {
|
||||
result.add(ac);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.add(ac);
|
||||
}
|
||||
}
|
||||
if (clear && !result.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
} else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
|
||||
for (ApiConfig ac : apiConfigs) {
|
||||
if (ac.access == ApiConfig.ALLOW) {
|
||||
result.add(ac);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end for
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,45 +95,45 @@ public class CallbackService {
|
||||
ServiceInstance si = service2instMap.get(r.service);
|
||||
if (si == null) {
|
||||
send = fizzWebClient.send2service(traceId, method, r.service, r.path, headers, body)
|
||||
.onErrorResume( crError(exchange, r, method, headers, body) );
|
||||
.onErrorResume( crError(exchange, r, method, headers, body) );
|
||||
} else {
|
||||
String uri = buildUri(req, si, r.path);
|
||||
send = fizzWebClient.send(traceId, method, uri, headers, body)
|
||||
.onErrorResume( crError(exchange, r, method, headers, body) );
|
||||
.onErrorResume( crError(exchange, r, method, headers, body) );
|
||||
}
|
||||
} else {
|
||||
send = aggregateService.request(WebUtils.getTraceId(exchange), WebUtils.getClientReqPathPrefix(exchange), method.name(), r.service, r.path, req.getQueryParams(), headers, body)
|
||||
.onErrorResume( arError(exchange, r, method, headers, body) );
|
||||
.onErrorResume( arError(exchange, r, method, headers, body) );
|
||||
}
|
||||
sends[i] = send;
|
||||
}
|
||||
return Flux.mergeSequential(sends)
|
||||
.collectList()
|
||||
.flatMap(
|
||||
sendResults -> {
|
||||
Object r = null;
|
||||
for (int i = 1; i < sendResults.size(); i++) {
|
||||
r = sendResults.get(i);
|
||||
if (r instanceof ClientResponse && !(r instanceof FizzFailClientResponse)) {
|
||||
clean((ClientResponse) r);
|
||||
}
|
||||
}
|
||||
r = sendResults.get(0);
|
||||
Throwable t = null;
|
||||
if (r instanceof FizzFailClientResponse) {
|
||||
t = ((FizzFailClientResponse) r).throwable;
|
||||
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
|
||||
} if (r instanceof FailAggregateResult) {
|
||||
t = ((FailAggregateResult) r).throwable;
|
||||
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
|
||||
} else if (r instanceof ClientResponse) {
|
||||
return genServerResponse(exchange, (ClientResponse) r);
|
||||
} else {
|
||||
return aggregateService.genAggregateResponse(exchange, (AggregateResult) r);
|
||||
}
|
||||
}
|
||||
)
|
||||
;
|
||||
.collectList()
|
||||
.flatMap(
|
||||
sendResults -> {
|
||||
Object r = null;
|
||||
for (int i = 1; i < sendResults.size(); i++) {
|
||||
r = sendResults.get(i);
|
||||
if (r instanceof ClientResponse && !(r instanceof FizzFailClientResponse)) {
|
||||
clean((ClientResponse) r);
|
||||
}
|
||||
}
|
||||
r = sendResults.get(0);
|
||||
Throwable t = null;
|
||||
if (r instanceof FizzFailClientResponse) {
|
||||
t = ((FizzFailClientResponse) r).throwable;
|
||||
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
|
||||
} if (r instanceof FailAggregateResult) {
|
||||
t = ((FailAggregateResult) r).throwable;
|
||||
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
|
||||
} else if (r instanceof ClientResponse) {
|
||||
return genServerResponse(exchange, (ClientResponse) r);
|
||||
} else {
|
||||
return aggregateService.genAggregateResponse(exchange, (AggregateResult) r);
|
||||
}
|
||||
}
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
private Function<Throwable, Mono<? extends ClientResponse>> crError(ServerWebExchange exchange, Receiver r, HttpMethod method, HttpHeaders headers, DataBuffer body) {
|
||||
@@ -201,14 +201,14 @@ public class CallbackService {
|
||||
log.debug(b.toString(), LogService.BIZ_ID, traceId);
|
||||
}
|
||||
return clientResp.writeWith(remoteResp.body(BodyExtractors.toDataBuffers()))
|
||||
.doOnError(throwable -> clean(remoteResp)).doOnCancel(() -> clean(remoteResp));
|
||||
.doOnError(throwable -> clean(remoteResp)).doOnCancel(() -> clean(remoteResp));
|
||||
}
|
||||
|
||||
public Mono<Result> replay(CallbackReplayReq req) {
|
||||
|
||||
HashSet<String> gatewayGroups = new HashSet<>();
|
||||
gatewayGroups.add(req.gatewayGroup);
|
||||
Result<ApiConfig> result = apiConfigService.get(gatewayGroups, req.app, req.service, req.method, req.path);
|
||||
Result<ApiConfig> result = apiConfigService.get(false, gatewayGroups, req.app, req.service, req.method, req.path);
|
||||
ApiConfig ac = result.data;
|
||||
if (ac == null) {
|
||||
return Mono.just(Result.fail("no api config for " + req.path));
|
||||
@@ -227,13 +227,13 @@ public class CallbackService {
|
||||
if (si != null) {
|
||||
String uri = buildUri("http", si, r.path);
|
||||
send = fizzWebClient.send(req.id, req.method, uri, req.headers, req.body)
|
||||
.onErrorResume( crError(req, r.service, r.path) );
|
||||
.onErrorResume( crError(req, r.service, r.path) );
|
||||
sends.add(send);
|
||||
}
|
||||
} else {
|
||||
String traceId = CommonConstants.TRACE_ID_PREFIX + req.id;
|
||||
send = aggregateService.request(traceId, aggrConfigPrefix, req.method.name(), r.service, r.path, null, req.headers, req.body)
|
||||
.onErrorResume( arError(req, r.service, r.path) );
|
||||
.onErrorResume( arError(req, r.service, r.path) );
|
||||
sends.add(send);
|
||||
}
|
||||
}
|
||||
@@ -243,11 +243,11 @@ public class CallbackService {
|
||||
for (ServiceTypePath stp : req.assignServices) {
|
||||
if (stp.type == ApiConfig.Type.SERVICE_DISCOVERY) {
|
||||
send = fizzWebClient.send2service(req.id, req.method, stp.service, stp.path, req.headers, req.body)
|
||||
.onErrorResume( crError(req, stp.service, stp.path) );
|
||||
.onErrorResume( crError(req, stp.service, stp.path) );
|
||||
} else {
|
||||
String traceId = CommonConstants.TRACE_ID_PREFIX + req.id;
|
||||
send = aggregateService.request(traceId, aggrConfigPrefix, req.method.name(), stp.service, stp.path, null, req.headers, req.body)
|
||||
.onErrorResume( arError(req, stp.service, stp.path) );
|
||||
.onErrorResume( arError(req, stp.service, stp.path) );
|
||||
}
|
||||
sends.add(send);
|
||||
}
|
||||
@@ -256,27 +256,27 @@ public class CallbackService {
|
||||
int ss = sends.size();
|
||||
Mono<Object>[] sendArr = sends.toArray(new Mono[ss]);
|
||||
return Flux.mergeSequential(sendArr)
|
||||
.collectList()
|
||||
.map(
|
||||
sendResults -> {
|
||||
int c = Result.SUCC;
|
||||
Throwable t = null;
|
||||
for (int i = 0; i < sendResults.size(); i++) {
|
||||
Object r = sendResults.get(i);
|
||||
if (r instanceof FizzFailClientResponse) {
|
||||
c = Result.FAIL;
|
||||
t = ((FizzFailClientResponse) r).throwable;
|
||||
} else if (r instanceof FailAggregateResult) {
|
||||
c = Result.FAIL;
|
||||
t = ((FailAggregateResult) r).throwable;
|
||||
} else if (r instanceof ClientResponse) {
|
||||
clean((ClientResponse) r);
|
||||
}
|
||||
}
|
||||
return Result.with(c, t);
|
||||
}
|
||||
)
|
||||
;
|
||||
.collectList()
|
||||
.map(
|
||||
sendResults -> {
|
||||
int c = Result.SUCC;
|
||||
Throwable t = null;
|
||||
for (int i = 0; i < sendResults.size(); i++) {
|
||||
Object r = sendResults.get(i);
|
||||
if (r instanceof FizzFailClientResponse) {
|
||||
c = Result.FAIL;
|
||||
t = ((FizzFailClientResponse) r).throwable;
|
||||
} else if (r instanceof FailAggregateResult) {
|
||||
c = Result.FAIL;
|
||||
t = ((FailAggregateResult) r).throwable;
|
||||
} else if (r instanceof ClientResponse) {
|
||||
clean((ClientResponse) r);
|
||||
}
|
||||
}
|
||||
return Result.with(c, t);
|
||||
}
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
private Function<Throwable, Mono<? extends AggregateResult>> arError(CallbackReplayReq req, String service, String path) {
|
||||
@@ -304,5 +304,4 @@ public class CallbackService {
|
||||
private void clean(ClientResponse cr) {
|
||||
cr.bodyToMono(Void.class).subscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import java.util.List;
|
||||
|
||||
public class Route {
|
||||
|
||||
public boolean dedicatedLine = false;
|
||||
|
||||
public byte type;
|
||||
|
||||
public HttpMethod method;
|
||||
@@ -64,6 +66,11 @@ public class Route {
|
||||
|
||||
public long retryInterval = 0;
|
||||
|
||||
public Route dedicatedLine(boolean b) {
|
||||
dedicatedLine = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Route type(int t) {
|
||||
type = (byte) t;
|
||||
return this;
|
||||
|
||||
@@ -292,7 +292,7 @@ public class RpcInstanceServiceImpl implements RpcInstanceService {
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
public void setIsDeleted(Integer isDeleted) {
|
||||
public void setDeleted(Integer isDeleted) {
|
||||
this.isDeleted = isDeleted;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ import java.util.Map;
|
||||
|
||||
public abstract class FizzEurekaHelper {
|
||||
|
||||
private FizzEurekaHelper() {
|
||||
}
|
||||
|
||||
public static FizzEurekaServiceRegistration getServiceRegistration(FizzEurekaProperties fizzEurekaProperties) {
|
||||
|
||||
InetUtils inetUtils = fizzEurekaProperties.applicationContext.getBean(InetUtils.class);
|
||||
|
||||
@@ -33,6 +33,9 @@ import java.util.Map;
|
||||
|
||||
public abstract class FizzNacosHelper {
|
||||
|
||||
private FizzNacosHelper() {
|
||||
}
|
||||
|
||||
public static FizzNacosServiceRegistration getServiceRegistration(FizzNacosProperties fizzNacosProperties) {
|
||||
fizzNacosProperties.init();
|
||||
NacosServiceRegistry nacosServiceRegistry = new NacosServiceRegistry(fizzNacosProperties);
|
||||
|
||||
@@ -39,8 +39,6 @@ public class ResourceRateLimitConfig {
|
||||
static final byte IP = 7;
|
||||
}
|
||||
|
||||
public static final int DELETED = 1;
|
||||
|
||||
public static final String NODE = "_global";
|
||||
|
||||
public static final String NODE_RESOURCE = buildResourceId(null, null, NODE, null, null);
|
||||
@@ -53,11 +51,7 @@ public class ResourceRateLimitConfig {
|
||||
|
||||
public static final String APP_DEFAULT_RESOURCE = buildResourceId(APP_DEFAULT, null, null, null, null);
|
||||
|
||||
private static final int ENABLE = 1;
|
||||
|
||||
private static final int UNABLE = 0;
|
||||
|
||||
public int isDeleted = 0;
|
||||
public boolean isDeleted = false;
|
||||
|
||||
public int id;
|
||||
|
||||
@@ -89,8 +83,14 @@ public class ResourceRateLimitConfig {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public void setDeleted(int v) {
|
||||
if (v == 1) {
|
||||
isDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnable(int v) {
|
||||
if (v == ENABLE) {
|
||||
if (v == 1) {
|
||||
enable = true;
|
||||
} else {
|
||||
enable = false;
|
||||
|
||||
@@ -77,9 +77,8 @@ public class ResourceRateLimitConfigService {
|
||||
if (k == ReactorUtils.OBJ) {
|
||||
return Flux.just(e);
|
||||
}
|
||||
Object v = e.getValue();
|
||||
log.info("rateLimitConfig: " + v.toString(), LogService.BIZ_ID, k.toString());
|
||||
String json = (String) v;
|
||||
String json = (String) e.getValue();
|
||||
log.info("rateLimitConfig: " + json, LogService.BIZ_ID, k.toString());
|
||||
try {
|
||||
ResourceRateLimitConfig rrlc = JacksonUtils.readValue(json, ResourceRateLimitConfig.class);
|
||||
oldResourceRateLimitConfigMapTmp.put(rrlc.id, rrlc);
|
||||
@@ -127,11 +126,11 @@ public class ResourceRateLimitConfigService {
|
||||
try {
|
||||
ResourceRateLimitConfig rrlc = JacksonUtils.readValue(json, ResourceRateLimitConfig.class);
|
||||
ResourceRateLimitConfig r = oldResourceRateLimitConfigMap.remove(rrlc.id);
|
||||
if (rrlc.isDeleted != ResourceRateLimitConfig.DELETED && r != null) {
|
||||
if (!rrlc.isDeleted && r != null) {
|
||||
resourceRateLimitConfigMap.remove(r.getResourceId());
|
||||
}
|
||||
updateResourceRateLimitConfigMap(rrlc, resourceRateLimitConfigMap);
|
||||
if (rrlc.isDeleted != ResourceRateLimitConfig.DELETED) {
|
||||
if (!rrlc.isDeleted) {
|
||||
oldResourceRateLimitConfigMap.put(rrlc.id, rrlc);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
@@ -155,7 +154,7 @@ public class ResourceRateLimitConfigService {
|
||||
|
||||
private void updateResourceRateLimitConfigMap(ResourceRateLimitConfig rrlc,
|
||||
Map<String, ResourceRateLimitConfig> resourceRateLimitConfigMap) {
|
||||
if (rrlc.isDeleted == ResourceRateLimitConfig.DELETED) {
|
||||
if (rrlc.isDeleted) {
|
||||
ResourceRateLimitConfig removedRrlc = resourceRateLimitConfigMap.remove(rrlc.getResourceId());
|
||||
log.info("remove " + removedRrlc);
|
||||
} else {
|
||||
|
||||
@@ -111,7 +111,7 @@ public abstract class WebUtils {
|
||||
|
||||
public static final String ADMIN_REQUEST = "ar@";
|
||||
|
||||
public static final String FIZZ_API_REQUEST = "far@";
|
||||
public static final String FIZZ_REQUEST = "fr@";
|
||||
|
||||
|
||||
private WebUtils() {
|
||||
@@ -121,8 +121,8 @@ public abstract class WebUtils {
|
||||
return exchange.getAttribute(ADMIN_REQUEST) != null;
|
||||
}
|
||||
|
||||
public static boolean isFizzApiReq(ServerWebExchange exchange) {
|
||||
return exchange.getAttribute(FIZZ_API_REQUEST) != null;
|
||||
public static boolean isFizzReq(ServerWebExchange exchange) {
|
||||
return exchange.getAttribute(FIZZ_REQUEST) != null;
|
||||
}
|
||||
|
||||
public static void setGatewayPrefix(String p) {
|
||||
@@ -149,6 +149,11 @@ public abstract class WebUtils {
|
||||
return exchange.getRequest().getHeaders().get(header);
|
||||
}
|
||||
|
||||
public static boolean isDedicatedLineRequest(ServerWebExchange exchange) {
|
||||
String v = exchange.getRequest().getHeaders().getFirst(SystemConfig.FIZZ_DL_ID);
|
||||
return v != null;
|
||||
}
|
||||
|
||||
public static String getAppId(ServerWebExchange exchange) {
|
||||
HttpHeaders headers = exchange.getRequest().getHeaders();
|
||||
for (int i = 0; i < appHeaders.size(); i++) {
|
||||
@@ -181,6 +186,18 @@ public abstract class WebUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getDedicatedLineId(ServerWebExchange exchange) {
|
||||
return getHeaderValue(exchange, SystemConfig.FIZZ_DL_ID);
|
||||
}
|
||||
|
||||
public static String getDedicatedLineTimestamp(ServerWebExchange exchange) {
|
||||
return getHeaderValue(exchange, SystemConfig.FIZZ_DL_TS);
|
||||
}
|
||||
|
||||
public static String getDedicatedLineSign(ServerWebExchange exchange) {
|
||||
return getHeaderValue(exchange, SystemConfig.FIZZ_DL_SIGN);
|
||||
}
|
||||
|
||||
public static String getClientService(ServerWebExchange exchange) {
|
||||
String svc = exchange.getAttribute(clientService);
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
package we.api.pairing;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import we.Fizz;
|
||||
import we.redis.RedisProperties;
|
||||
import we.redis.RedisServerConfiguration;
|
||||
import we.redis.RedisTemplateConfiguration;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.ReflectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@TestPropertySource("/application.properties")
|
||||
@SpringJUnitConfig(classes = {RedisProperties.class, RedisTemplateConfiguration.class, RedisServerConfiguration.class})
|
||||
public class ApiPairingDocSetServiceTests {
|
||||
|
||||
@Resource
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
|
||||
|
||||
ApiPairingDocSetService apiPairingDocSetService;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws NoSuchFieldException {
|
||||
apiPairingDocSetService = new ApiPairingDocSetService();
|
||||
ReflectionUtils.set(apiPairingDocSetService, "rt", reactiveStringRedisTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
void initTest() throws Throwable {
|
||||
|
||||
Fizz.context = new GenericApplicationContext();
|
||||
Fizz.context.refresh();
|
||||
|
||||
Map<String, String> hash = new HashMap<>();
|
||||
hash.put("c", "{\"id\":1,\"name\":\"DocSet1\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
|
||||
hash.put("d", "{\"id\":2,\"name\":\"DocSet2\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
|
||||
// hash.put("a", "{\"isDeleted\":1,\"id\":1,\"name\":\"DocSet1\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
|
||||
// hash.put("b", "{\"isDeleted\":1,\"id\":2,\"name\":\"DocSet2\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
|
||||
stringRedisTemplate.opsForHash().putAll("fizz_api_pairing_doc", hash);
|
||||
|
||||
apiPairingDocSetService.init();
|
||||
Map<Long, ApiPairingDocSet> docSetMap = apiPairingDocSetService.getDocSetMap();
|
||||
Map<String, Set<ApiPairingDocSet>> appDocSetMap = apiPairingDocSetService.getAppDocSetMap();
|
||||
Map<String, Set<ApiPairingDocSet>> serviceExistsInDocSetMap = apiPairingDocSetService.getServiceExistsInDocSetMap();
|
||||
Map<Object, Map<String, Set<ApiPairingDocSet>>> methodPathExistsInDocSetMap = apiPairingDocSetService.getMethodPathExistsInDocSetMap();
|
||||
// System.err.println("docSetMap: " + JacksonUtils.writeValueAsString(docSetMap));
|
||||
// System.err.println("appDocSetMap: " + JacksonUtils.writeValueAsString(appDocSetMap));
|
||||
// System.err.println("serviceExistsInDocSetMap: " + JacksonUtils.writeValueAsString(serviceExistsInDocSetMap));
|
||||
// System.err.println("methodPathExistsInDocSetMap: " + JacksonUtils.writeValueAsString(methodPathExistsInDocSetMap));
|
||||
|
||||
boolean b = apiPairingDocSetService.existsDocSetMatch("app1", HttpMethod.GET, "we-meb", "/getMebInfo");
|
||||
Assert.assertTrue(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package we.dedicated_line;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import we.Fizz;
|
||||
import we.redis.RedisProperties;
|
||||
import we.redis.RedisServerConfiguration;
|
||||
import we.redis.RedisTemplateConfiguration;
|
||||
import we.util.ReflectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author hongqiaowei
|
||||
*/
|
||||
|
||||
@TestPropertySource("/application.properties")
|
||||
@SpringJUnitConfig(classes = {RedisProperties.class, RedisTemplateConfiguration.class, RedisServerConfiguration.class})
|
||||
public class DedicatedLineServiceTests {
|
||||
|
||||
@Resource
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
|
||||
|
||||
DedicatedLineService dedicatedLineService;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws NoSuchFieldException {
|
||||
dedicatedLineService = new DedicatedLineService();
|
||||
ReflectionUtils.set(dedicatedLineService, "rt", reactiveStringRedisTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
void initTest() throws Throwable {
|
||||
Fizz.context = new GenericApplicationContext();
|
||||
Fizz.context.refresh();
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,13 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import we.redis.RedisProperties;
|
||||
import we.redis.RedisServerConfiguration;
|
||||
import we.redis.RedisTemplateConfiguration;
|
||||
import we.stats.ratelimit.ResourceRateLimitConfigService;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.ReflectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
@@ -31,17 +27,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
public class ApiConfig2appsServiceTests {
|
||||
|
||||
@Resource
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
|
||||
|
||||
ApiConifg2appsService apiConifg2appsService;
|
||||
ApiConfig2appsService apiConfig2AppsService;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws NoSuchFieldException {
|
||||
apiConifg2appsService = new ApiConifg2appsService();
|
||||
ReflectionUtils.set(apiConifg2appsService, "rt", reactiveStringRedisTemplate);
|
||||
apiConfig2AppsService = new ApiConfig2appsService();
|
||||
ReflectionUtils.set(apiConfig2AppsService, "rt", reactiveStringRedisTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -55,10 +51,10 @@ public class ApiConfig2appsServiceTests {
|
||||
stringRedisTemplate.opsForSet().add("fizz_api_config_app:61_0", "app_b", "app_c");
|
||||
stringRedisTemplate.opsForSet().add("fizz_api_config_app:61_1", "app_d");
|
||||
|
||||
apiConifg2appsService.init();
|
||||
apiConfig2AppsService.init();
|
||||
Thread.sleep(4000);
|
||||
|
||||
Map<Integer, Set<String>> apiConfig2appsMap = apiConifg2appsService.getApiConfig2appsMap();
|
||||
Map<Integer, Set<String>> apiConfig2appsMap = apiConfig2AppsService.getApiConfig2appsMap();
|
||||
// System.err.println("r: " + JacksonUtils.writeValueAsString(apiConfig2appsMap));
|
||||
assertTrue(apiConfig2appsMap.get(61).contains("app_c"));
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>fizz-gateway-community</artifactId>
|
||||
<groupId>com.fizzgate</groupId>
|
||||
<version>2.3.3-beta6</version>
|
||||
<version>2.3.4-beta1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -258,7 +258,7 @@
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
|
||||
@@ -19,15 +19,19 @@ package we.plugin.dedicatedline.auth;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.api.pairing.ApiPairingDocSetService;
|
||||
import we.config.SystemConfig;
|
||||
|
||||
import we.dedicated_line.DedicatedLineService;
|
||||
|
||||
|
||||
import we.plugin.FizzPluginFilter;
|
||||
import we.plugin.FizzPluginFilterChain;
|
||||
import we.util.ReactorUtils;
|
||||
@@ -46,21 +50,27 @@ public class DedicatedLineApiAuthPluginFilter implements FizzPluginFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DedicatedLineApiAuthPluginFilter.class);
|
||||
|
||||
public static final String DEDICATED_LINE_API_AUTH_PLUGIN_FILTER = "dedicatedLineCodecPlugin";
|
||||
|
||||
|
||||
@Resource
|
||||
private ApiPairingDocSetService apiPairingDocSetService;
|
||||
private DedicatedLineService dedicatedLineService;
|
||||
|
||||
public static final String DEDICATED_LINE_API_AUTH_PLUGIN_FILTER = "dedicatedLineCodecPlugin";
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config) {
|
||||
String traceId = WebUtils.getTraceId(exchange);
|
||||
try {
|
||||
String appId = WebUtils.getAppId(exchange);
|
||||
|
||||
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
|
||||
String service = WebUtils.getClientService(exchange);
|
||||
String path = WebUtils.getClientReqPath(exchange);
|
||||
HttpMethod method = exchange.getRequest().getMethod();
|
||||
if (apiPairingDocSetService.existsDocSetMatch(appId, method, service, path)) {
|
||||
if (dedicatedLineService.auth(dedicatedLineId, method, service, path)) {
|
||||
|
||||
// Go to next plugin
|
||||
Mono next = FizzPluginFilterChain.next(exchange);
|
||||
return next.defaultIfEmpty(ReactorUtils.NULL).flatMap(nil -> {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>fizz-gateway-community</artifactId>
|
||||
<groupId>com.fizzgate</groupId>
|
||||
<version>2.3.3-beta6</version>
|
||||
<version>2.3.4-beta1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -26,7 +26,7 @@ we.fizz.AggregateService,\
|
||||
we.fizz.ConfigLoader,\
|
||||
we.listener.AggregateChannelListener,\
|
||||
we.plugin.auth.ApiConfigService,\
|
||||
we.plugin.auth.ApiConifg2appsService,\
|
||||
we.plugin.auth.ApiConfig2appsService,\
|
||||
we.plugin.auth.AppService,\
|
||||
we.plugin.auth.AuthPluginFilter,\
|
||||
we.plugin.auth.GatewayGroupService,\
|
||||
@@ -46,4 +46,4 @@ we.proxy.NacosUriSelector,\
|
||||
we.proxy.RpcInstanceServiceImpl,\
|
||||
we.stats.ratelimit.ResourceRateLimitConfigService,\
|
||||
we.global_resource.GlobalResourceService,\
|
||||
we.api.pairing.FizzApiPairingWebServer
|
||||
we.dedicated_line.DedicatedLineWebServer
|
||||
|
||||
20
pom.xml
20
pom.xml
@@ -7,7 +7,7 @@
|
||||
<!--<java.version>1.8</java.version>-->
|
||||
<spring-boot.version>2.2.13.RELEASE</spring-boot.version>
|
||||
<spring-framework.version>5.2.18.RELEASE</spring-framework.version>
|
||||
<reactor-bom.version>Dysprosium-SR24</reactor-bom.version>
|
||||
<reactor-bom.version>Dysprosium-SR25</reactor-bom.version>
|
||||
<lettuce.version>5.3.7.RELEASE</lettuce.version>
|
||||
<nacos.cloud.version>2.2.6.RELEASE</nacos.cloud.version>
|
||||
<netty.version>4.1.70.Final</netty.version>
|
||||
@@ -37,7 +37,7 @@
|
||||
<artifactId>fizz-gateway-community</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>fizz gateway community</description>
|
||||
<version>2.3.3-beta6</version>
|
||||
<version>2.3.4-beta1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>fizz-common</module>
|
||||
@@ -433,13 +433,13 @@
|
||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||
<version>${netty-tcnative.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
<version>5.7.16</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -596,16 +596,4 @@
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
</profiles>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>nexus-releases</id>
|
||||
<name>local private nexus</name>
|
||||
<url>http://gzmaven.bestwehotel.com/nexus/content/repositories/releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>nexus-snapshots</id>
|
||||
<name>local private nexus</name>
|
||||
<url>http://gzmaven.bestwehotel.com/nexus/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
||||
|
||||
Reference in New Issue
Block a user