feat: multi app support
This commit is contained in:
@@ -27,7 +27,7 @@ http://demo.fizzgate.com/
|
|||||||
|
|
||||||
account/password:`admin`/`Aa123!`
|
account/password:`admin`/`Aa123!`
|
||||||
|
|
||||||
health checking url:http://demo.fizzgate.com/serviceConfigs
|
health checking url:http://demo.fizzgate.com/admin/health
|
||||||
|
|
||||||
API access:http://demo.fizzgate.com/proxy/[Service Name]/[API Path]
|
API access:http://demo.fizzgate.com/proxy/[Service Name]/[API Path]
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ http://demo.fizzgate.com/
|
|||||||
|
|
||||||
账号/密码:`admin`/`Aa123!`
|
账号/密码:`admin`/`Aa123!`
|
||||||
|
|
||||||
健康检查地址:http://demo.fizzgate.com/serviceConfigs
|
健康检查地址:http://demo.fizzgate.com/admin/health
|
||||||
|
|
||||||
API地址:http://demo.fizzgate.com/proxy/[服务名]/[API Path]
|
API地址:http://demo.fizzgate.com/proxy/[服务名]/[API Path]
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/config")
|
@RequestMapping(value = "/admin/config")
|
||||||
public class ConfigController {
|
public class ConfigController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
|||||||
50
src/main/java/we/controller/HealthCheckController.java
Normal file
50
src/main/java/we/controller/HealthCheckController.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import we.plugin.auth.ApiConfigService;
|
||||||
|
import we.plugin.auth.AppService;
|
||||||
|
import we.plugin.auth.GatewayGroupService;
|
||||||
|
import we.stats.ratelimit.ResourceRateLimitConfigService;
|
||||||
|
import we.util.Constants;
|
||||||
|
import we.util.DateTimeUtils;
|
||||||
|
import we.util.JacksonUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author hongqiaowei
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin")
|
||||||
|
public class HealthCheckController {
|
||||||
|
|
||||||
|
@GetMapping("/health")
|
||||||
|
public Mono<String> health(ServerWebExchange exchange) {
|
||||||
|
long mills = System.currentTimeMillis();
|
||||||
|
String now = DateTimeUtils.toDate(mills, Constants.DatetimePattern.DP23);
|
||||||
|
return Mono.just(now + " ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ import java.util.stream.Collectors;
|
|||||||
* @author zhongjie
|
* @author zhongjie
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/managerConfig")
|
@RequestMapping(value = "/admin/managerConfig")
|
||||||
public class ManagerConfigController {
|
public class ManagerConfigController {
|
||||||
@NacosValue(value = "${fizz.manager.config.key:fizz-manager-key}", autoRefreshed = true)
|
@NacosValue(value = "${fizz.manager.config.key:fizz-manager-key}", autoRefreshed = true)
|
||||||
@Value("${fizz.manager.config.key:fizz-manager-key}")
|
@Value("${fizz.manager.config.key:fizz-manager-key}")
|
||||||
|
|||||||
@@ -53,10 +53,12 @@ public class ApiConfig {
|
|||||||
|
|
||||||
private static final String match_all = "/**";
|
private static final String match_all = "/**";
|
||||||
|
|
||||||
// @JsonIgnore
|
private static final int ENABLE = 1;
|
||||||
|
|
||||||
|
private static final int UNABLE = 0;
|
||||||
|
|
||||||
public int id; // tb_api_auth.id
|
public int id; // tb_api_auth.id
|
||||||
|
|
||||||
// @JsonIgnore
|
|
||||||
public int isDeleted = 0; // tb_api_auth.is_deleted
|
public int isDeleted = 0; // tb_api_auth.is_deleted
|
||||||
|
|
||||||
public Set<String> gatewayGroups = Stream.of(GatewayGroup.DEFAULT).collect(Collectors.toSet());
|
public Set<String> gatewayGroups = Stream.of(GatewayGroup.DEFAULT).collect(Collectors.toSet());
|
||||||
@@ -67,28 +69,27 @@ public class ApiConfig {
|
|||||||
|
|
||||||
public HttpMethod method = HttpMethod.X;
|
public HttpMethod method = HttpMethod.X;
|
||||||
|
|
||||||
// public String path = String.valueOf(Constants.Symbol.FORWARD_SLASH);
|
|
||||||
public String path = match_all;
|
public String path = match_all;
|
||||||
|
|
||||||
public boolean exactMatch = false;
|
public boolean exactMatch = false;
|
||||||
|
|
||||||
public String backendPath;
|
public String backendPath;
|
||||||
|
|
||||||
public Set<String> apps = Stream.of(App.ALL_APP).collect(Collectors.toSet());
|
// public Set<String> apps = Stream.of(App.ALL_APP).collect(Collectors.toSet());
|
||||||
|
|
||||||
@JsonProperty("proxyMode")
|
@JsonProperty("proxyMode")
|
||||||
public byte type = Type.SERVICE_DISCOVERY;
|
public byte type = Type.SERVICE_DISCOVERY;
|
||||||
|
|
||||||
private AtomicInteger counter = new AtomicInteger(-1);
|
private AtomicInteger counter = new AtomicInteger(-1);
|
||||||
|
|
||||||
// public List<String> backendUrls;
|
|
||||||
|
|
||||||
public List<String> httpHostPorts;
|
public List<String> httpHostPorts;
|
||||||
|
|
||||||
public char access = ALLOW;
|
public char access = ALLOW;
|
||||||
|
|
||||||
public List<PluginConfig> pluginConfigs;
|
public List<PluginConfig> pluginConfigs;
|
||||||
|
|
||||||
|
public boolean checkApp = false;
|
||||||
|
|
||||||
public static boolean isAntPathPattern(String path) {
|
public static boolean isAntPathPattern(String path) {
|
||||||
boolean uriVar = false;
|
boolean uriVar = false;
|
||||||
for (int i = 0; i < path.length(); i++) {
|
for (int i = 0; i < path.length(); i++) {
|
||||||
@@ -120,18 +121,18 @@ public class ApiConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApp(String as) {
|
// public void setApp(String as) {
|
||||||
apps.remove(App.ALL_APP);
|
// apps.remove(App.ALL_APP);
|
||||||
if (StringUtils.isBlank(as)) {
|
// if (StringUtils.isBlank(as)) {
|
||||||
apps.add("*");
|
// apps.add("*");
|
||||||
} else {
|
// } else {
|
||||||
Arrays.stream(StringUtils.split(as, ',')).forEach(
|
// Arrays.stream(StringUtils.split(as, ',')).forEach(
|
||||||
a -> {
|
// a -> {
|
||||||
apps.add(a.trim());
|
// apps.add(a.trim());
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void setPath(String p) {
|
public void setPath(String p) {
|
||||||
if (StringUtils.isNotBlank(p)) {
|
if (StringUtils.isNotBlank(p)) {
|
||||||
@@ -155,15 +156,13 @@ public class ApiConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @JsonIgnore
|
public void setAppEnable(int v) {
|
||||||
// public String getNextBackendUrl() {
|
if (v == ENABLE) {
|
||||||
// int idx = counter.incrementAndGet();
|
checkApp = true;
|
||||||
// if (idx < 0) {
|
} else {
|
||||||
// counter.set(0);
|
checkApp = false;
|
||||||
// idx = 0;
|
}
|
||||||
// }
|
}
|
||||||
// return backendUrls.get(idx % backendUrls.size());
|
|
||||||
// }
|
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public String getNextHttpHostPort() {
|
public String getNextHttpHostPort() {
|
||||||
@@ -182,6 +181,20 @@ public class ApiConfig {
|
|||||||
return UrlTransformUtils.transform(path, backendPath, reqPath);
|
return UrlTransformUtils.transform(path, backendPath, reqPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof ApiConfig) {
|
||||||
|
ApiConfig that = (ApiConfig) obj;
|
||||||
|
return this.id == that.id;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return JacksonUtils.writeValueAsString(this);
|
return JacksonUtils.writeValueAsString(this);
|
||||||
|
|||||||
43
src/main/java/we/plugin/auth/ApiConfig2apps.java
Normal file
43
src/main/java/we/plugin/auth/ApiConfig2apps.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package we.plugin.auth;
|
||||||
|
|
||||||
|
import we.util.JacksonUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author hongqiaowei
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ApiConfig2apps {
|
||||||
|
|
||||||
|
public static final int DELETED = 1;
|
||||||
|
|
||||||
|
public int id;
|
||||||
|
|
||||||
|
public int isDeleted = 0;
|
||||||
|
|
||||||
|
public List<String> apps;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JacksonUtils.writeValueAsString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,6 @@
|
|||||||
package we.plugin.auth;
|
package we.plugin.auth;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.config.annotation.NacosValue;
|
import com.alibaba.nacos.api.config.annotation.NacosValue;
|
||||||
import com.ctrip.framework.apollo.model.ConfigChange;
|
|
||||||
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
|
|
||||||
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -31,12 +28,11 @@ import org.springframework.http.HttpHeaders;
|
|||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import we.flume.clients.log4j2appender.LogService;
|
|
||||||
import we.config.AggregateRedisConfig;
|
import we.config.AggregateRedisConfig;
|
||||||
|
import we.flume.clients.log4j2appender.LogService;
|
||||||
import we.util.*;
|
import we.util.*;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
@@ -71,48 +67,6 @@ public class ApiConfigService {
|
|||||||
|
|
||||||
private Map<Integer, ApiConfig> apiConfigMap = new HashMap<>(128);
|
private Map<Integer, ApiConfig> apiConfigMap = new HashMap<>(128);
|
||||||
|
|
||||||
// TODO XXX
|
|
||||||
@Value("${serviceWhiteList:x}")
|
|
||||||
private String serviceWhiteList;
|
|
||||||
private Set<String> whiteListSet = new HashSet<>(196);
|
|
||||||
@ApolloConfigChangeListener
|
|
||||||
private void configChangeListter(ConfigChangeEvent cce) {
|
|
||||||
cce.changedKeys().forEach(
|
|
||||||
k -> {
|
|
||||||
ConfigChange cc = cce.getChange(k);
|
|
||||||
if (cc.getPropertyName().equalsIgnoreCase("serviceWhiteList")) {
|
|
||||||
this.updateServiceWhiteList(cc.getOldValue(), cc.getNewValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateServiceWhiteList(String oldValue, String newValue) {
|
|
||||||
if (ObjectUtils.nullSafeEquals(oldValue, newValue)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.info("old service white list: " + oldValue);
|
|
||||||
serviceWhiteList = newValue;
|
|
||||||
afterServiceWhiteListSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NacosValue(value = "${serviceWhiteList:x}", autoRefreshed = true)
|
|
||||||
public void setServiceWhiteList(String serviceWhiteList) {
|
|
||||||
this.updateServiceWhiteList(this.serviceWhiteList, serviceWhiteList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterServiceWhiteListSet() {
|
|
||||||
if (StringUtils.isNotBlank(serviceWhiteList)) {
|
|
||||||
whiteListSet.clear();
|
|
||||||
Arrays.stream(StringUtils.split(serviceWhiteList, Constants.Symbol.COMMA)).forEach(s -> {
|
|
||||||
whiteListSet.add(s);
|
|
||||||
});
|
|
||||||
log.info("new service white list: " + whiteListSet.toString());
|
|
||||||
} else {
|
|
||||||
log.info("no service white list");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NacosValue(value = "${need-auth:false}", autoRefreshed = true)
|
@NacosValue(value = "${need-auth:false}", autoRefreshed = true)
|
||||||
@Value("${need-auth:false}")
|
@Value("${need-auth:false}")
|
||||||
private boolean needAuth;
|
private boolean needAuth;
|
||||||
@@ -123,6 +77,9 @@ public class ApiConfigService {
|
|||||||
@Resource
|
@Resource
|
||||||
private AppService appService;
|
private AppService appService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApiConifg2appsService apiConifg2appsService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private GatewayGroupService gatewayGroupService;
|
private GatewayGroupService gatewayGroupService;
|
||||||
|
|
||||||
@@ -136,8 +93,6 @@ public class ApiConfigService {
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() throws Throwable {
|
public void init() throws Throwable {
|
||||||
|
|
||||||
afterServiceWhiteListSet(); // TODO XXX
|
|
||||||
|
|
||||||
final Throwable[] throwable = new Throwable[1];
|
final Throwable[] throwable = new Throwable[1];
|
||||||
Throwable error = Mono.just(Objects.requireNonNull(rt.opsForHash().entries(fizzApiConfig)
|
Throwable error = Mono.just(Objects.requireNonNull(rt.opsForHash().entries(fizzApiConfig)
|
||||||
.defaultIfEmpty(new AbstractMap.SimpleEntry<>(ReactorUtils.OBJ, ReactorUtils.OBJ)).onErrorStop().doOnError(t -> {
|
.defaultIfEmpty(new AbstractMap.SimpleEntry<>(ReactorUtils.OBJ, ReactorUtils.OBJ)).onErrorStop().doOnError(t -> {
|
||||||
@@ -226,6 +181,7 @@ public class ApiConfigService {
|
|||||||
log.info("no " + ac.service + " config to delete");
|
log.info("no " + ac.service + " config to delete");
|
||||||
} else {
|
} else {
|
||||||
sc.remove(ac);
|
sc.remove(ac);
|
||||||
|
apiConifg2appsService.remove(ac.id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sc == null) {
|
if (sc == null) {
|
||||||
@@ -260,8 +216,6 @@ public class ApiConfigService {
|
|||||||
|
|
||||||
CUSTOM_AUTH_REJECT ("custom auth reject"),
|
CUSTOM_AUTH_REJECT ("custom auth reject"),
|
||||||
|
|
||||||
SERVICE_NOT_OPEN ("service not open"),
|
|
||||||
|
|
||||||
CANT_ACCESS_SERVICE_API ("cant access service api");
|
CANT_ACCESS_SERVICE_API ("cant access service api");
|
||||||
|
|
||||||
private String reason;
|
private String reason;
|
||||||
@@ -275,6 +229,21 @@ public class ApiConfigService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ApiConfig getApiConfig(String service, HttpMethod method, String path, String gatewayGroup, String app) {
|
||||||
|
ServiceConfig sc = serviceConfigMap.get(service);
|
||||||
|
if (sc != null) {
|
||||||
|
Set<ApiConfig> acs = sc.getApiConfigs(method, path, gatewayGroup);
|
||||||
|
if (acs != null) {
|
||||||
|
for (ApiConfig ac : acs) {
|
||||||
|
if (apiConifg2appsService.contains(ac.id, app)) {
|
||||||
|
return ac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Mono<Object> canAccess(ServerWebExchange exchange) {
|
public Mono<Object> canAccess(ServerWebExchange exchange) {
|
||||||
ServerHttpRequest req = exchange.getRequest();
|
ServerHttpRequest req = exchange.getRequest();
|
||||||
HttpHeaders hdrs = req.getHeaders();
|
HttpHeaders hdrs = req.getHeaders();
|
||||||
@@ -286,11 +255,6 @@ public class ApiConfigService {
|
|||||||
private Mono<Object> canAccess(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String secretKey,
|
private Mono<Object> canAccess(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String secretKey,
|
||||||
String service, HttpMethod method, String path) {
|
String service, HttpMethod method, String path) {
|
||||||
|
|
||||||
// if (openServiceWhiteList) {
|
|
||||||
// if (!whiteListSet.contains(service)) { // TODO XXX
|
|
||||||
// return Mono.just(Access.SERVICE_NOT_OPEN);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
ServiceConfig sc = serviceConfigMap.get(service);
|
ServiceConfig sc = serviceConfigMap.get(service);
|
||||||
if (sc == null) {
|
if (sc == null) {
|
||||||
if (!needAuth) {
|
if (!needAuth) {
|
||||||
@@ -301,8 +265,8 @@ public class ApiConfigService {
|
|||||||
} else {
|
} else {
|
||||||
String api = ThreadContext.getStringBuilder().append(service).append(Constants.Symbol.BLANK).append(method.name()).append(Constants.Symbol.BLANK + path).toString();
|
String api = ThreadContext.getStringBuilder().append(service).append(Constants.Symbol.BLANK).append(method.name()).append(Constants.Symbol.BLANK + path).toString();
|
||||||
ApiConfig ac0 = null;
|
ApiConfig ac0 = null;
|
||||||
for (String g : gatewayGroupService.currentGatewayGroupSet) { // compatible
|
for (String g : gatewayGroupService.currentGatewayGroupSet) {
|
||||||
ac0 = sc.getApiConfig(method, path, g, app);
|
ac0 = getApiConfig(service, method, path, g, app);
|
||||||
if (ac0 != null) {
|
if (ac0 != null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -315,9 +279,9 @@ public class ApiConfigService {
|
|||||||
return logWarnAndResult(api + " no api config", Access.NO_API_CONFIG);
|
return logWarnAndResult(api + " no api config", Access.NO_API_CONFIG);
|
||||||
}
|
}
|
||||||
} else if (gatewayGroupService.currentGatewayGroupIn(ac.gatewayGroups)) {
|
} else if (gatewayGroupService.currentGatewayGroupIn(ac.gatewayGroups)) {
|
||||||
if (ac.apps.contains(App.ALL_APP)) {
|
if (!ac.checkApp) {
|
||||||
return allow(api, ac);
|
return allow(api, ac);
|
||||||
} else if (app != null && ac.apps.contains(app)) {
|
} else if (app != null && apiConifg2appsService.contains(ac.id, app) ) {
|
||||||
if (ac.access == ApiConfig.ALLOW) {
|
if (ac.access == ApiConfig.ALLOW) {
|
||||||
App a = appService.getApp(app);
|
App a = appService.getApp(app);
|
||||||
if (a.useWhiteList && !a.allow(ip)) {
|
if (a.useWhiteList && !a.allow(ip)) {
|
||||||
|
|||||||
110
src/main/java/we/plugin/auth/ApiConifg2appsService.java
Normal file
110
src/main/java/we/plugin/auth/ApiConifg2appsService.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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.plugin.auth;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import we.config.AggregateRedisConfig;
|
||||||
|
import we.flume.clients.log4j2appender.LogService;
|
||||||
|
import we.util.Constants;
|
||||||
|
import we.util.JacksonUtils;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author hongqiaowei
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApiConifg2appsService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ApiConifg2appsService.class);
|
||||||
|
|
||||||
|
private static final String fizzApiConfigAppChannel = "fizz_api_config_app_channel";
|
||||||
|
|
||||||
|
private Map<Integer/* api config id */, Set<String/* app */>> apiConfig2appsMap = new HashMap<>(128);
|
||||||
|
|
||||||
|
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
|
||||||
|
private ReactiveStringRedisTemplate rt;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() throws Throwable {
|
||||||
|
rt.listenToChannel(fizzApiConfigAppChannel)
|
||||||
|
.doOnError(
|
||||||
|
t -> {
|
||||||
|
log.error("lsn api config 2 apps channel", t);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.doOnComplete(
|
||||||
|
() -> {
|
||||||
|
log.info("success to lsn on api config 2 apps channel");
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.doOnNext(
|
||||||
|
msg -> {
|
||||||
|
String json = msg.getMessage();
|
||||||
|
log.info(json, LogService.BIZ_ID, "ac2as" + System.currentTimeMillis());
|
||||||
|
try {
|
||||||
|
ApiConfig2apps data = JacksonUtils.readValue(json, ApiConfig2apps.class);
|
||||||
|
updateApiConfig2appsMap(data);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error(Constants.Symbol.EMPTY, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.subscribe()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateApiConfig2appsMap(ApiConfig2apps data) {
|
||||||
|
Set<String> apps = apiConfig2appsMap.get(data.id);
|
||||||
|
if (data.isDeleted == ApiConfig2apps.DELETED) {
|
||||||
|
if (apps != null) {
|
||||||
|
apps.removeAll(data.apps);
|
||||||
|
log.info("remove " + data.apps);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (apps == null) {
|
||||||
|
apps = new HashSet<>(32);
|
||||||
|
apiConfig2appsMap.put(data.id, apps);
|
||||||
|
}
|
||||||
|
apps.addAll(data.apps);
|
||||||
|
log.info("add " + data.apps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(int api, String app) {
|
||||||
|
Set<String> apps = apiConfig2appsMap.get(api);
|
||||||
|
if (apps == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return apps.contains(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> remove(int id) {
|
||||||
|
return apiConfig2appsMap.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
import we.util.JacksonUtils;
|
import we.util.JacksonUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hongqiaowei
|
* @author hongqiaowei
|
||||||
@@ -30,65 +32,86 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class GatewayGroup2apiConfig {
|
public class GatewayGroup2apiConfig {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GatewayGroup2apiConfig.class);
|
// private static final Logger log = LoggerFactory.getLogger(GatewayGroup2apiConfig.class);
|
||||||
|
|
||||||
private Map<String/*gg*/, Map<String/*a*/, ApiConfig>> configMap = new HashMap<>(6);
|
// private Map<String/*gg*/, Map<String/*a*/, ApiConfig>> configMap = new HashMap<>(6);
|
||||||
|
private Map<String/*gg*/, Set<ApiConfig>> configMap = new HashMap<>(6);
|
||||||
|
|
||||||
public Map<String, Map<String, ApiConfig>> getConfigMap() {
|
// public Map<String, Map<String, ApiConfig>> getConfigMap() {
|
||||||
return configMap;
|
// return configMap;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void setConfigMap(Map<String, Map<String, ApiConfig>> configMap) {
|
// public void setConfigMap(Map<String, Map<String, ApiConfig>> configMap) {
|
||||||
this.configMap = configMap;
|
// this.configMap = configMap;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void add(ApiConfig ac) {
|
public void add(ApiConfig ac) {
|
||||||
for (String gg : ac.gatewayGroups) {
|
for (String gg : ac.gatewayGroups) {
|
||||||
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
|
// Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
|
||||||
if (app2apiConfigMap == null) {
|
// if (app2apiConfigMap == null) {
|
||||||
app2apiConfigMap = new HashMap<>();
|
// app2apiConfigMap = new HashMap<>();
|
||||||
configMap.put(gg, app2apiConfigMap);
|
// configMap.put(gg, app2apiConfigMap);
|
||||||
}
|
// }
|
||||||
for (String a : ac.apps) {
|
// for (String a : ac.apps) {
|
||||||
app2apiConfigMap.put(a, ac);
|
// app2apiConfigMap.put(a, ac);
|
||||||
log.info("expose " + ac + " to " + gg + " group and " + a + " app");
|
// log.info("expose " + ac + " to " + gg + " group and " + a + " app");
|
||||||
|
// }
|
||||||
|
Set<ApiConfig> acs = configMap.get(gg);
|
||||||
|
if (acs == null) {
|
||||||
|
acs = new HashSet<>(6);
|
||||||
|
configMap.put(gg, acs);
|
||||||
}
|
}
|
||||||
|
acs.add(ac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(ApiConfig ac) {
|
public void remove(ApiConfig ac) {
|
||||||
for (String gg : ac.gatewayGroups) {
|
for (String gg : ac.gatewayGroups) {
|
||||||
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
|
// Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
|
||||||
if (app2apiConfigMap != null) {
|
// if (app2apiConfigMap != null) {
|
||||||
for (String a : ac.apps) {
|
// for (String a : ac.apps) {
|
||||||
ApiConfig r = app2apiConfigMap.remove(a);
|
// ApiConfig r = app2apiConfigMap.remove(a);
|
||||||
log.info("remove " + r + " from " + gg + " group and " + a + " app");
|
// log.info("remove " + r + " from " + gg + " group and " + a + " app");
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
Set<ApiConfig> acs = configMap.get(gg);
|
||||||
|
if (acs != null) {
|
||||||
|
acs.remove(ac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(ApiConfig ac) {
|
public void update(ApiConfig ac) {
|
||||||
for (String gg : ac.gatewayGroups) {
|
for (String gg : ac.gatewayGroups) {
|
||||||
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
|
// Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
|
||||||
if (app2apiConfigMap == null) {
|
// if (app2apiConfigMap == null) {
|
||||||
app2apiConfigMap = new HashMap<>();
|
// app2apiConfigMap = new HashMap<>();
|
||||||
configMap.put(gg, app2apiConfigMap);
|
// configMap.put(gg, app2apiConfigMap);
|
||||||
}
|
// }
|
||||||
for (String a : ac.apps) {
|
// for (String a : ac.apps) {
|
||||||
ApiConfig old = app2apiConfigMap.put(a, ac);
|
// ApiConfig old = app2apiConfigMap.put(a, ac);
|
||||||
log.info(gg + " group and " + a + " app update " + old + " with " + ac);
|
// log.info(gg + " group and " + a + " app update " + old + " with " + ac);
|
||||||
|
// }
|
||||||
|
Set<ApiConfig> acs = configMap.get(gg);
|
||||||
|
if (acs == null) {
|
||||||
|
acs = new HashSet<>(6);
|
||||||
|
configMap.put(gg, acs);
|
||||||
}
|
}
|
||||||
|
acs.add(ac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApiConfig get(String gatewayGroup, String app) {
|
// public ApiConfig get(String gatewayGroup, String app) {
|
||||||
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gatewayGroup);
|
// Map<String, ApiConfig> app2apiConfigMap = configMap.get(gatewayGroup);
|
||||||
if (app2apiConfigMap == null) {
|
// if (app2apiConfigMap == null) {
|
||||||
return null;
|
// return null;
|
||||||
} else {
|
// } else {
|
||||||
return app2apiConfigMap.get(app);
|
// return app2apiConfigMap.get(app);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public Set<ApiConfig> get(String gatewayGroup) {
|
||||||
|
return configMap.get(gatewayGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -111,17 +111,25 @@ public class ServiceConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @JsonIgnore
|
||||||
|
// public ApiConfig getApiConfig(HttpMethod method, String path, String gatewayGroup, String app) {
|
||||||
|
// GatewayGroup2apiConfig r = getApiConfig(method, path);
|
||||||
|
// if (r == null) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// if (StringUtils.isBlank(app)) {
|
||||||
|
// app = App.ALL_APP;
|
||||||
|
// }
|
||||||
|
// return r.get(gatewayGroup, app);
|
||||||
|
// }
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public ApiConfig getApiConfig(HttpMethod method, String path, String gatewayGroup, String app) {
|
public Set<ApiConfig> getApiConfigs(HttpMethod method, String path, String gatewayGroup) {
|
||||||
// GatewayGroup2appsToApiConfig r = getApiConfig0(method, path);
|
|
||||||
GatewayGroup2apiConfig r = getApiConfig(method, path);
|
GatewayGroup2apiConfig r = getApiConfig(method, path);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(app)) {
|
return r.get(gatewayGroup);
|
||||||
app = App.ALL_APP;
|
|
||||||
}
|
|
||||||
return r.get(gatewayGroup, app);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private GatewayGroup2apiConfig getApiConfig(HttpMethod method, String reqPath) {
|
private GatewayGroup2apiConfig getApiConfig(HttpMethod method, String reqPath) {
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ public class WebUtilsTests {
|
|||||||
MockServerHttpRequest mr = MockServerHttpRequest.get("http://127.0.0.1:8600/proxytest/test/ybiz").build();
|
MockServerHttpRequest mr = MockServerHttpRequest.get("http://127.0.0.1:8600/proxytest/test/ybiz").build();
|
||||||
MockServerWebExchange me = MockServerWebExchange.from(mr);
|
MockServerWebExchange me = MockServerWebExchange.from(mr);
|
||||||
String cs = WebUtils.getClientService(me);
|
String cs = WebUtils.getClientService(me);
|
||||||
System.err.println(cs);
|
// System.err.println(cs);
|
||||||
String crpp = WebUtils.getClientReqPathPrefix(me);
|
String crpp = WebUtils.getClientReqPathPrefix(me);
|
||||||
System.err.println(crpp);
|
// System.err.println(crpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user