feat: support tsf gw. (#1697)
Co-authored-by: shedfreewu <49236872+shedfreewu@users.noreply.github.com>pull/1698/head
parent
2e5bb9f65a
commit
da9b66f8d8
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.tencent.cloud.metadata.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
|
||||
public class HttpServletRequestHeaderWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private Map<String, String> addHeaders;
|
||||
|
||||
public HttpServletRequestHeaderWrapper(HttpServletRequest request, Map<String, String> addHeaders) {
|
||||
super(request);
|
||||
this.addHeaders = addHeaders;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
if (addHeaders.containsKey(name)) {
|
||||
return addHeaders.get(name);
|
||||
}
|
||||
else {
|
||||
return super.getHeader(name);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.tencent.cloud.common.constant.MetadataConstant;
|
||||
import com.tencent.cloud.common.tsf.TsfContextUtils;
|
||||
import com.tencent.polaris.api.utils.CollectionUtils;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
|
||||
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
|
||||
import com.tencent.polaris.plugins.connector.consul.service.common.TagConstant;
|
||||
import com.tencent.polaris.plugins.router.lane.LaneRouter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.tsf.core.entity.Metadata;
|
||||
import org.springframework.tsf.core.entity.Tag;
|
||||
|
||||
public final class TsfTagUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TsfTagUtils.class);
|
||||
|
||||
private TsfTagUtils() {
|
||||
}
|
||||
|
||||
public static List<Tag> deserializeTagList(String buffer) {
|
||||
if (StringUtils.isEmpty(buffer)) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.asList(JacksonUtils.deserialize(UrlUtils.decode(buffer), Tag[].class));
|
||||
}
|
||||
|
||||
public static Metadata deserializeMetadata(String buffer) {
|
||||
if (StringUtils.isEmpty(buffer)) {
|
||||
return null;
|
||||
}
|
||||
return JacksonUtils.deserialize(UrlUtils.decode(buffer), Metadata.class);
|
||||
}
|
||||
|
||||
public static Map<String, String> getTsfMetadataMap(Map<String, String> calleeTransitiveHeaders, Map<String, String> disposableMetadata,
|
||||
Map<String, String> customMetadata, Map<String, String> applicationMetadata) {
|
||||
|
||||
Map<String, String> tsfMetadataMap = new HashMap<>();
|
||||
Set<String> tsfUserTagKeys = new HashSet<>();
|
||||
// user tags
|
||||
List<Tag> tsfUserTags = new ArrayList<>();
|
||||
List<Tag> tsfSystemTags = new ArrayList<>();
|
||||
Tag laneTag = null;
|
||||
|
||||
for (Map.Entry<String, String> entry : customMetadata.entrySet()) {
|
||||
if (tsfUserTagKeys.contains(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
Tag tag = new Tag(entry.getKey(), entry.getValue(), Tag.ControlFlag.TRANSITIVE);
|
||||
tsfUserTags.add(tag);
|
||||
tsfUserTagKeys.add(entry.getKey());
|
||||
if (LaneRouter.TRAFFIC_STAIN_LABEL.equals(entry.getKey()) && entry.getValue().contains("/")) {
|
||||
String lane = entry.getValue().split("/")[1];
|
||||
laneTag = new Tag("lane", lane, Tag.ControlFlag.TRANSITIVE);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, String> entry : disposableMetadata.entrySet()) {
|
||||
if (tsfUserTagKeys.contains(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
Tag tag = new Tag(entry.getKey(), entry.getValue());
|
||||
tsfUserTags.add(tag);
|
||||
tsfUserTagKeys.add(entry.getKey());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : calleeTransitiveHeaders.entrySet()) {
|
||||
if (entry.getKey().startsWith(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX)) {
|
||||
String key = entry.getKey().substring(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX_LENGTH);
|
||||
String value = entry.getValue();
|
||||
if (tsfUserTagKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Tag tag = new Tag(key, value, Tag.ControlFlag.TRANSITIVE);
|
||||
tsfUserTags.add(tag);
|
||||
tsfUserTagKeys.add(key);
|
||||
if (LaneRouter.TRAFFIC_STAIN_LABEL.equals(key) && value.contains("/")) {
|
||||
String lane = value.split("/")[1];
|
||||
laneTag = new Tag("lane", lane, Tag.ControlFlag.TRANSITIVE);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (laneTag != null) {
|
||||
tsfSystemTags.add(laneTag);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(tsfUserTags)) {
|
||||
tsfMetadataMap.put(MetadataConstant.HeaderName.TSF_TAGS, JacksonUtils.serialize2Json(tsfUserTags));
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(tsfSystemTags)) {
|
||||
tsfMetadataMap.put(MetadataConstant.HeaderName.TSF_SYSTEM_TAG, JacksonUtils.serialize2Json(tsfSystemTags));
|
||||
}
|
||||
|
||||
Metadata metadata = new Metadata();
|
||||
for (Map.Entry<String, String> entry : applicationMetadata.entrySet()) {
|
||||
switch (entry.getKey()) {
|
||||
case MetadataConstants.LOCAL_SERVICE:
|
||||
metadata.setServiceName(entry.getValue());
|
||||
break;
|
||||
case MetadataConstants.LOCAL_IP:
|
||||
metadata.setLocalIp(entry.getValue());
|
||||
break;
|
||||
case TsfMetadataConstants.TSF_GROUP_ID:
|
||||
metadata.setGroupId(entry.getValue());
|
||||
break;
|
||||
case TsfMetadataConstants.TSF_APPLICATION_ID:
|
||||
metadata.setApplicationId(entry.getValue());
|
||||
break;
|
||||
case TsfMetadataConstants.TSF_INSTNACE_ID:
|
||||
metadata.setInstanceId(entry.getValue());
|
||||
break;
|
||||
case TsfMetadataConstants.TSF_PROG_VERSION:
|
||||
metadata.setApplicationVersion(entry.getValue());
|
||||
break;
|
||||
case TsfMetadataConstants.TSF_NAMESPACE_ID:
|
||||
metadata.setNamespaceId(entry.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
tsfMetadataMap.put(MetadataConstant.HeaderName.TSF_METADATA, JacksonUtils.serialize2Json(metadata));
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("calleeTransitiveHeaders:{}, disposableMetadata: {}, customMetadata: {}, applicationMetadata: {}, tsfMetadataMap:{}",
|
||||
calleeTransitiveHeaders, disposableMetadata, customMetadata, applicationMetadata, tsfMetadataMap);
|
||||
}
|
||||
|
||||
return tsfMetadataMap;
|
||||
}
|
||||
|
||||
public static void updateTsfMetadata(Map<String, String> mergedTransitiveMetadata,
|
||||
Map<String, String> mergedDisposableMetadata, Map<String, String> mergedApplicationMetadata, Map<String, String> addHeaders,
|
||||
AtomicReference<String> callerIp, String encodedUserTagList, String encodedSystemTagList, String encodedMetadata) {
|
||||
|
||||
if (!TsfContextUtils.isOnlyTsfConsulEnabled()) {
|
||||
return;
|
||||
}
|
||||
List<Tag> tsfUserTagList = TsfTagUtils.deserializeTagList(encodedUserTagList);
|
||||
int tagSize = Optional.ofNullable(tsfUserTagList).map(List::size).orElse(0);
|
||||
Map<String, String> tsfTransitiveMetadata = new HashMap<>(tagSize);
|
||||
Map<String, String> tsfDisposableMetadata = new HashMap<>(tagSize);
|
||||
if (CollectionUtils.isNotEmpty(tsfUserTagList)) {
|
||||
for (Tag tag : tsfUserTagList) {
|
||||
if (Tag.ControlFlag.TRANSITIVE.equals(tag.getFlags())) {
|
||||
tsfTransitiveMetadata.put(tag.getKey(), tag.getValue());
|
||||
}
|
||||
tsfDisposableMetadata.put(tag.getKey(), tag.getValue());
|
||||
}
|
||||
mergedTransitiveMetadata.putAll(tsfTransitiveMetadata);
|
||||
mergedDisposableMetadata.putAll(tsfDisposableMetadata);
|
||||
}
|
||||
|
||||
List<Tag> tsfSystemTagList = TsfTagUtils.deserializeTagList(encodedSystemTagList);
|
||||
if (CollectionUtils.isNotEmpty(tsfSystemTagList)) {
|
||||
for (Tag tag : tsfSystemTagList) {
|
||||
if ("lane".equals(tag.getKey())) {
|
||||
mergedTransitiveMetadata.put(LaneRouter.TRAFFIC_STAIN_LABEL, UrlUtils.encode("tsf/" + tag.getValue()));
|
||||
addHeaders.put(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX + LaneRouter.TRAFFIC_STAIN_LABEL,
|
||||
UrlUtils.encode("tsf/" + tag.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Metadata metadata = TsfTagUtils.deserializeMetadata(encodedMetadata);
|
||||
if (metadata != null) {
|
||||
if (StringUtils.isNotEmpty(metadata.getLocalIp())) {
|
||||
callerIp.set(metadata.getLocalIp());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metadata.getApplicationId())) {
|
||||
mergedApplicationMetadata.put(TsfMetadataConstants.TSF_APPLICATION_ID, metadata.getApplicationId());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metadata.getGroupId())) {
|
||||
mergedApplicationMetadata.put(TsfMetadataConstants.TSF_GROUP_ID, metadata.getGroupId());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metadata.getApplicationVersion())) {
|
||||
mergedApplicationMetadata.put(TsfMetadataConstants.TSF_PROG_VERSION, metadata.getApplicationVersion());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metadata.getNamespaceId())) {
|
||||
mergedApplicationMetadata.put(TsfMetadataConstants.TSF_NAMESPACE_ID, metadata.getNamespaceId());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metadata.getServiceName())) {
|
||||
mergedApplicationMetadata.put(MetadataConstants.LOCAL_SERVICE, metadata.getServiceName());
|
||||
mergedApplicationMetadata.put(TagConstant.SYSTEM_FIELD.SOURCE_SERVICE_NAME, metadata.getServiceName());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(metadata.getLocalIp())) {
|
||||
mergedApplicationMetadata.put(MetadataConstants.LOCAL_IP, metadata.getLocalIp());
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("mergedTransitiveMetadata:{}, mergedDisposableMetadata: {}, mergedApplicationMetadata: {},"
|
||||
+ " addHeaders:{}, encodedUserTagList:{}, encodedSystemTagList:{}, encodedMetadata:{}, callerIp:{}",
|
||||
mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata,
|
||||
addHeaders, encodedUserTagList, encodedSystemTagList, encodedMetadata, callerIp.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.tsf.core.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
public class Metadata implements Serializable {
|
||||
|
||||
@JsonProperty("ai")
|
||||
private String applicationId = "";
|
||||
|
||||
@JsonProperty("av")
|
||||
private String applicationVersion = "";
|
||||
|
||||
@JsonProperty("sn")
|
||||
private String serviceName = "";
|
||||
|
||||
@JsonProperty("ii")
|
||||
private String instanceId = "";
|
||||
|
||||
@JsonProperty("gi")
|
||||
private String groupId = "";
|
||||
|
||||
@JsonProperty("li")
|
||||
private String localIp = "";
|
||||
|
||||
@JsonProperty("lis")
|
||||
private String localIps = "";
|
||||
|
||||
@JsonProperty("ni")
|
||||
private String namespaceId = "";
|
||||
|
||||
@JsonProperty("pi")
|
||||
private boolean preferIpv6;
|
||||
|
||||
public Metadata() {
|
||||
}
|
||||
|
||||
public String getApplicationId() {
|
||||
return applicationId;
|
||||
}
|
||||
|
||||
public void setApplicationId(String applicationId) {
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
// 其实是程序包的版本,但是这里程序包概念没啥用,直接用应用来表示
|
||||
public String getApplicationVersion() {
|
||||
return applicationVersion;
|
||||
}
|
||||
|
||||
public void setApplicationVersion(String applicationVersion) {
|
||||
this.applicationVersion = applicationVersion;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
public void setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
public String getInstanceId() {
|
||||
return instanceId;
|
||||
}
|
||||
|
||||
public void setInstanceId(String instanceId) {
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getLocalIp() {
|
||||
if (preferIpv6 && !StringUtils.isEmpty(localIps)) {
|
||||
for (String ip : localIps.split(",")) {
|
||||
if (ip.contains(":")) {
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
return localIp;
|
||||
}
|
||||
|
||||
public void setLocalIp(String localIp) {
|
||||
this.localIp = localIp;
|
||||
}
|
||||
|
||||
public String getLocalIps() {
|
||||
return localIps;
|
||||
}
|
||||
|
||||
public void setLocalIps(String localIps) {
|
||||
this.localIps = localIps;
|
||||
}
|
||||
|
||||
public String getNamespaceId() {
|
||||
return namespaceId;
|
||||
}
|
||||
|
||||
public void setNamespaceId(String namespaceId) {
|
||||
this.namespaceId = namespaceId;
|
||||
}
|
||||
|
||||
public boolean isPreferIpv6() {
|
||||
return preferIpv6;
|
||||
}
|
||||
|
||||
public void setPreferIpv6(boolean preferIpv6) {
|
||||
this.preferIpv6 = preferIpv6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Metadata{" +
|
||||
"applicationId='" + applicationId + '\'' +
|
||||
", applicationVersion='" + applicationVersion + '\'' +
|
||||
", serviceName='" + serviceName + '\'' +
|
||||
", instanceId='" + instanceId + '\'' +
|
||||
", groupId='" + groupId + '\'' +
|
||||
", localIp='" + localIp + '\'' +
|
||||
", namespaceId='" + namespaceId + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.common.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.tsf.core.entity.Tag;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* test for {@link TsfTagUtils}.
|
||||
*/
|
||||
public class TsfTagUtilsTest {
|
||||
|
||||
@Test
|
||||
public void deserializeTagList() {
|
||||
String data = "%5B%7B%22k%22%3A%22tsf-gateway-ratelimit-context%22%2C%22v%22%3A%22grp-vyiwvq5t%22%2C%22f%22%3A%5B%5D%7D%2C%7B%22k%22%3A%22feat%22%2C%22v%22%3A%22test%22%2C%22f%22%3A%5B%220%22%5D%7D%5D";
|
||||
List<Tag> tagList = TsfTagUtils.deserializeTagList(data);
|
||||
for (Tag tag : tagList) {
|
||||
assertThat(tag.getKey()).isNotNull();
|
||||
assertThat(tag.getValue()).isNotNull();
|
||||
assertThat(tag.getFlags()).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>tsf-example</artifactId>
|
||||
<groupId>com.tencent.cloud</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>msgw-scg</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tencent.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-tencent-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.tsf.msgw.scg;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.tsf.annotation.EnableTsf;
|
||||
|
||||
/**
|
||||
* @author seanlxliu
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableTsf
|
||||
public class ScgApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ScgApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
server:
|
||||
port: 8080
|
||||
error:
|
||||
include-exception: true
|
||||
spring:
|
||||
application:
|
||||
name: msgw-scg
|
||||
cloud:
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: false
|
||||
httpclient:
|
||||
# The connect timeout in millis, the default is 45s.
|
||||
connectTimeout: 200
|
||||
responseTimeout: 10s
|
||||
consul:
|
||||
enabled: true
|
||||
scheme: HTTP
|
||||
|
||||
logging:
|
||||
level:
|
||||
root: INFO
|
||||
file:
|
||||
name: /tsf-demo-logs/${spring.application.name}/root.log
|
||||
pattern:
|
||||
level: "%-5level [${spring.application.name},%mdc{trace_id},%mdc{span_id},]"
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.plugin.gateway.context;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.constant.AuthMode;
|
||||
import com.tencent.tsf.gateway.core.constant.CommonStatus;
|
||||
import com.tencent.tsf.gateway.core.constant.HeaderName;
|
||||
import com.tencent.tsf.gateway.core.constant.TsfAlgType;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
import com.tencent.tsf.gateway.core.util.TsfSignUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
public final class AuthCheckUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthCheckUtil.class);
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private AuthCheckUtil() {
|
||||
}
|
||||
|
||||
public static void signCheck(ServerWebExchange exchange, GroupContext groupContext) {
|
||||
AuthMode authMode = Optional.ofNullable(groupContext.getAuth()).map(GroupContext.ContextAuth::getType)
|
||||
.orElse(null);
|
||||
if (!AuthMode.SECRET.equals(authMode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String secretId = exchange.getRequest().getHeaders().getFirst(HeaderName.APP_KEY);
|
||||
if (StringUtils.isEmpty(secretId)) {
|
||||
logger.error("[signCheck] secretId is empty. path: {}", exchange.getRequest().getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_BAD_REQUEST, "RequestHeader x-mg-secretid is required");
|
||||
}
|
||||
String nonce = exchange.getRequest().getHeaders().getFirst(HeaderName.NONCE);
|
||||
if (StringUtils.isEmpty(nonce)) {
|
||||
logger.error("[signCheck] nonce is empty. path: {}", exchange.getRequest().getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_BAD_REQUEST, "RequestHeader x-mg-nonce is required");
|
||||
}
|
||||
String alg = exchange.getRequest().getHeaders().getFirst(HeaderName.ALG);
|
||||
if (StringUtils.isEmpty(alg)) {
|
||||
logger.error("[signCheck] alg is empty. path: {}", exchange.getRequest().getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_BAD_REQUEST, "RequestHeader x-mg-alg is required");
|
||||
}
|
||||
String clientSign = exchange.getRequest().getHeaders().getFirst(HeaderName.SIGN);
|
||||
if (StringUtils.isEmpty(clientSign)) {
|
||||
logger.error("[signCheck] sign is empty. path: {}", exchange.getRequest().getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "RequestHeader x-mg-sign is wrong");
|
||||
}
|
||||
|
||||
TsfAlgType algType = TsfAlgType.getSecurityCode(alg);
|
||||
|
||||
List<GroupContext.ContextSecret> secretList = groupContext.getAuth().getSecrets();
|
||||
|
||||
GroupContext.ContextSecret secret = null;
|
||||
if (secretList != null) {
|
||||
for (GroupContext.ContextSecret s : secretList) {
|
||||
if (s.getId().equals(secretId)) {
|
||||
secret = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (secret == null) {
|
||||
logger.error("[signCheck] secret is not found. secretId:{}, path: {}", secretId, exchange.getRequest()
|
||||
.getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "GroupSecret Not Found");
|
||||
}
|
||||
if (CommonStatus.DISABLED.getStatus().equals(secret.getStatus())) {
|
||||
logger.error("[signCheck] secret is invalid. secretId:{}, path: {}", secretId, exchange.getRequest()
|
||||
.getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_BAD_REQUEST, "GroupSecret Invalid");
|
||||
}
|
||||
|
||||
String expiredTime = secret.getExpiredTime();
|
||||
LocalDateTime expiredDateTime = LocalDateTime.parse(expiredTime, FORMATTER);
|
||||
LocalDateTime nowDateTime = LocalDateTime.now();
|
||||
boolean expired = nowDateTime.isAfter(expiredDateTime);
|
||||
|
||||
if (expired) {
|
||||
logger.error("[signCheck] secret is expired. secretId:{}, path: {}", secretId, exchange.getRequest()
|
||||
.getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "GroupSecret Expired");
|
||||
}
|
||||
|
||||
|
||||
String serverSign = TsfSignUtil.generate(nonce, secretId, secret.getKey(), algType);
|
||||
if (!StringUtils.equals(clientSign, serverSign)) {
|
||||
logger.error("[signCheck] sign check failed. secretId:{}, nonce:{}, secretKey:{}, clientSign:{}, path: {}",
|
||||
secretId, nonce, secret.getKey(), clientSign, exchange.getRequest().getURI().getPath());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "GroupSecret Check Failed");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.plugin.gateway.context;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.ConsulRawClient;
|
||||
import com.ecwid.consul.v1.QueryParams;
|
||||
import com.ecwid.consul.v1.Response;
|
||||
import com.ecwid.consul.v1.kv.model.GetValue;
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
|
||||
import com.tencent.polaris.api.utils.CollectionUtils;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.polaris.client.util.NamedThreadFactory;
|
||||
import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl;
|
||||
import com.tencent.polaris.plugins.configuration.connector.consul.ConsulConfigConstants;
|
||||
import com.tencent.polaris.plugins.configuration.connector.consul.ConsulConfigContext;
|
||||
import com.tencent.tsf.gateway.core.constant.AuthMode;
|
||||
import com.tencent.tsf.gateway.core.constant.GatewayConstant;
|
||||
import com.tencent.tsf.gateway.core.model.GatewayAllResult;
|
||||
import com.tencent.tsf.gateway.core.model.Group;
|
||||
import com.tencent.tsf.gateway.core.model.GroupApi;
|
||||
import com.tencent.tsf.gateway.core.model.GroupApiResult;
|
||||
import com.tencent.tsf.gateway.core.model.GroupResult;
|
||||
import com.tencent.tsf.gateway.core.model.GroupSecret;
|
||||
import com.tencent.tsf.gateway.core.model.PathRewriteResult;
|
||||
import com.tencent.tsf.gateway.core.model.PathWildcardResult;
|
||||
import com.tencent.tsf.gateway.core.model.PathWildcardRule;
|
||||
import com.tencent.tsf.gateway.core.model.PluginInstanceInfoResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
|
||||
import org.springframework.cloud.gateway.filter.FilterDefinition;
|
||||
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import static com.tencent.polaris.api.config.plugin.DefaultPlugins.SERVER_CONNECTOR_CONSUL;
|
||||
|
||||
public class GatewayConsulRepo {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GatewayConsulRepo.class);
|
||||
|
||||
private final ContextGatewayProperties contextGatewayProperties;
|
||||
|
||||
private final ContextGatewayPropertiesManager contextGatewayPropertiesManager;
|
||||
|
||||
private final ApplicationEventPublisher publisher;
|
||||
private final AtomicLong gatewayGroupIndex = new AtomicLong(-1);
|
||||
private final AtomicLong commonPluginIndex = new AtomicLong(-1);
|
||||
private ConsulClient consulClient;
|
||||
private ConsulConfigContext consulConfigContext;
|
||||
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2, new NamedThreadFactory("consul-gateway-watch", true));
|
||||
|
||||
public GatewayConsulRepo(ContextGatewayProperties contextGatewayProperties,
|
||||
PolarisSDKContextManager polarisSDKContextManager,
|
||||
ContextGatewayPropertiesManager contextGatewayPropertiesManager,
|
||||
ApplicationEventPublisher publisher, String tsfGroupId) {
|
||||
this.contextGatewayProperties = contextGatewayProperties;
|
||||
this.contextGatewayPropertiesManager = contextGatewayPropertiesManager;
|
||||
this.publisher = publisher;
|
||||
|
||||
List<ServerConnectorConfigImpl> serverConnectorConfigs = polarisSDKContextManager.getSDKContext().getConfig()
|
||||
.getGlobal().getServerConnectors();
|
||||
if (serverConnectorConfigs == null || serverConnectorConfigs.size() != 1 || !SERVER_CONNECTOR_CONSUL.equals(serverConnectorConfigs.get(0)
|
||||
.getProtocol())) {
|
||||
logger.warn("GatewayConsulRepo not enable, serverConnectorConfigs:{}", serverConnectorConfigs);
|
||||
return;
|
||||
}
|
||||
|
||||
// init consul client
|
||||
ServerConnectorConfigImpl connectorConfig = serverConnectorConfigs.get(0);
|
||||
|
||||
if (CollectionUtils.isEmpty(connectorConfig.getAddresses())) {
|
||||
logger.warn("GatewayConsulRepo not enable, connectorConfig:{}", connectorConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
String address = connectorConfig.getAddresses().get(0);
|
||||
int lastIndex = address.lastIndexOf(":");
|
||||
String agentHost = address.substring(0, lastIndex);
|
||||
int agentPort = Integer.parseInt(address.substring(lastIndex + 1));
|
||||
logger.info("Connect to consul config server : [{}].", address);
|
||||
|
||||
consulClient = new ConsulClient(new ConsulRawClient(agentHost, agentPort));
|
||||
initConsulConfigContext(connectorConfig);
|
||||
|
||||
Response<List<GetValue>> listResponse = consulClient.getKVValues("tsf_gateway/" + tsfGroupId, consulConfigContext.getAclToken());
|
||||
|
||||
gatewayGroupIndex.set(listResponse.getConsulIndex());
|
||||
if (listResponse.getValue() != null) {
|
||||
refreshGatewayGroupConfig(parseGroupResponse(listResponse));
|
||||
}
|
||||
|
||||
scheduledExecutorService.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
Response<List<GetValue>> watchResponse = consulClient.getKVValues("tsf_gateway/" + tsfGroupId,
|
||||
consulConfigContext.getAclToken(), new QueryParams(consulConfigContext.getWaitTime(), gatewayGroupIndex.get()));
|
||||
// 404
|
||||
if (watchResponse.getValue() == null) {
|
||||
return;
|
||||
}
|
||||
// 200
|
||||
Long newIndex = watchResponse.getConsulIndex();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[watch group] index: {}, newIndex: {}", gatewayGroupIndex.get(), newIndex);
|
||||
}
|
||||
if (newIndex != null && !Objects.equals(gatewayGroupIndex.get(), newIndex)) {
|
||||
gatewayGroupIndex.set(newIndex);
|
||||
refreshGatewayGroupConfig(parseGroupResponse(watchResponse));
|
||||
this.publisher.publishEvent(new RefreshRoutesEvent(this));
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Gateway config watch error.", e);
|
||||
try {
|
||||
Thread.sleep(consulConfigContext.getConsulErrorSleep());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error("error in sleep, msg: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}, consulConfigContext.getDelay(), consulConfigContext.getDelay(), TimeUnit.MILLISECONDS);
|
||||
|
||||
|
||||
scheduledExecutorService.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
Response<List<GetValue>> watchResponse = consulClient.getKVValues("tsf_gateway/common/plugin",
|
||||
consulConfigContext.getAclToken(), new QueryParams(consulConfigContext.getWaitTime(), commonPluginIndex.get()));
|
||||
// 404
|
||||
if (watchResponse.getValue() == null) {
|
||||
return;
|
||||
}
|
||||
// 200
|
||||
Long newIndex = watchResponse.getConsulIndex();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[watch plugin] index: {}, newIndex: {}", commonPluginIndex.get(), newIndex);
|
||||
}
|
||||
if (newIndex != null && !Objects.equals(commonPluginIndex.get(), newIndex)) {
|
||||
commonPluginIndex.set(listResponse.getConsulIndex());
|
||||
parsePluginResponse(watchResponse);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Gateway plugin watch error.", e);
|
||||
try {
|
||||
Thread.sleep(consulConfigContext.getConsulErrorSleep());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error("error in sleep, msg: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}, consulConfigContext.getDelay(), consulConfigContext.getDelay(), TimeUnit.MILLISECONDS);
|
||||
|
||||
}
|
||||
|
||||
private void initConsulConfigContext(ServerConnectorConfigImpl connectorConfig) {
|
||||
// init consul config context.
|
||||
consulConfigContext = new ConsulConfigContext();
|
||||
// token
|
||||
String tokenStr = connectorConfig.getToken();
|
||||
if (StringUtils.isNotBlank(tokenStr)) {
|
||||
consulConfigContext.setAclToken(tokenStr);
|
||||
}
|
||||
|
||||
Map<String, String> metadata = connectorConfig.getMetadata();
|
||||
if (CollectionUtils.isNotEmpty(metadata)) {
|
||||
String waitTimeStr = metadata.get(ConsulConfigConstants.WAIT_TIME_KEY);
|
||||
if (StringUtils.isNotBlank(waitTimeStr)) {
|
||||
try {
|
||||
int waitTime = Integer.parseInt(waitTimeStr);
|
||||
consulConfigContext.setWaitTime(waitTime);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("wait time string {} is not integer.", waitTimeStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
String delayStr = metadata.get(ConsulConfigConstants.DELAY_KEY);
|
||||
if (StringUtils.isNotBlank(delayStr)) {
|
||||
try {
|
||||
int delay = Integer.parseInt(delayStr);
|
||||
consulConfigContext.setDelay(delay);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("delay string {} is not integer.", delayStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
String consulErrorSleepStr = metadata.get(ConsulConfigConstants.CONSUL_ERROR_SLEEP_KEY);
|
||||
if (StringUtils.isNotBlank(consulErrorSleepStr)) {
|
||||
try {
|
||||
long consulErrorSleep = Long.parseLong(consulErrorSleepStr);
|
||||
consulConfigContext.setConsulErrorSleep(consulErrorSleep);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("delay string {} is not integer.", consulErrorSleepStr, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePluginResponse(Response<List<GetValue>> listResponse) {
|
||||
|
||||
PluginInstanceInfoResult pluginInstanceInfoResult = new PluginInstanceInfoResult();
|
||||
pluginInstanceInfoResult.setResult(new ArrayList<>());
|
||||
|
||||
for (GetValue getValue : listResponse.getValue()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[parseResponse] Received plugin data: {}", getValue.getDecodedValue());
|
||||
}
|
||||
PluginInstanceInfoResult temp = JacksonUtils.deserialize(getValue.getDecodedValue(), PluginInstanceInfoResult.class);
|
||||
pluginInstanceInfoResult.getResult().addAll(temp.getResult());
|
||||
}
|
||||
|
||||
saveAsFile(JacksonUtils.serialize2Json(pluginInstanceInfoResult), GatewayConstant.PLUGIN_FILE_NAME);
|
||||
|
||||
contextGatewayProperties.setPlugins(pluginInstanceInfoResult.getResult());
|
||||
contextGatewayPropertiesManager.refreshPlugins(contextGatewayProperties.getPlugins());
|
||||
|
||||
}
|
||||
|
||||
private GatewayAllResult parseGroupResponse(Response<List<GetValue>> listResponse) {
|
||||
GroupResult groupResult = null;
|
||||
GroupApiResult groupApiResult = new GroupApiResult();
|
||||
groupApiResult.setResult(new ArrayList<>());
|
||||
|
||||
PathRewriteResult pathRewriteResult = new PathRewriteResult();
|
||||
PathWildcardResult pathWildcardResult = null;
|
||||
|
||||
|
||||
for (GetValue getValue : listResponse.getValue()) {
|
||||
String key = getValue.getKey();
|
||||
String[] keySplit = key.split("/");
|
||||
// format example: tsf_gateway/group-xxx/group/data
|
||||
if (keySplit.length < 4) {
|
||||
continue;
|
||||
}
|
||||
switch (keySplit[2]) {
|
||||
case GatewayConstant.GROUP_FILE_NAME:
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[parseResponse] Received group data: {}", getValue.getDecodedValue());
|
||||
}
|
||||
groupResult = JacksonUtils.deserialize(getValue.getDecodedValue(), GroupResult.class);
|
||||
break;
|
||||
case GatewayConstant.API_FILE_NAME:
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[parseResponse] Received api data: {}", getValue.getDecodedValue());
|
||||
}
|
||||
GroupApiResult temp = JacksonUtils.deserialize(getValue.getDecodedValue(), GroupApiResult.class);
|
||||
groupApiResult.getResult().addAll(temp.getResult());
|
||||
break;
|
||||
case GatewayConstant.PATH_REWRITE_FILE_NAME:
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[parseResponse] Received path rewrite data: {}", getValue.getDecodedValue());
|
||||
}
|
||||
pathRewriteResult = JacksonUtils.deserialize(getValue.getDecodedValue(), PathRewriteResult.class);
|
||||
break;
|
||||
case GatewayConstant.PATH_WILDCARD_FILE_NAME:
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("[parseResponse] Received path wildcard data: {}", getValue.getDecodedValue());
|
||||
}
|
||||
pathWildcardResult = JacksonUtils.deserialize(getValue.getDecodedValue(), PathWildcardResult.class);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
saveAsFile(JacksonUtils.serialize2Json(groupResult), GatewayConstant.GROUP_FILE_NAME);
|
||||
saveAsFile(JacksonUtils.serialize2Json(groupApiResult), GatewayConstant.API_FILE_NAME);
|
||||
saveAsFile(JacksonUtils.serialize2Json(pathRewriteResult), GatewayConstant.PATH_REWRITE_FILE_NAME);
|
||||
saveAsFile(JacksonUtils.serialize2Json(pathWildcardResult), GatewayConstant.PATH_WILDCARD_FILE_NAME);
|
||||
|
||||
return new GatewayAllResult(groupResult, groupApiResult, pathRewriteResult, pathWildcardResult);
|
||||
}
|
||||
|
||||
private void refreshGatewayGroupConfig(GatewayAllResult gatewayAllResult) {
|
||||
GroupResult groupResult = gatewayAllResult.getGroupResult();
|
||||
GroupApiResult groupApiResult = gatewayAllResult.getGroupApiResult();
|
||||
PathRewriteResult pathRewriteResult = gatewayAllResult.getPathRewriteResult();
|
||||
PathWildcardResult pathWildcardResult = gatewayAllResult.getPathWildcardResult();
|
||||
|
||||
Map<String, RouteDefinition> routes = new HashMap<>();
|
||||
Map<String, GroupContext> groups = new HashMap<>();
|
||||
|
||||
if (groupResult != null && groupResult.getResult() != null) {
|
||||
for (Group group : groupResult.getResult()) {
|
||||
routes.put(group.getGroupId(), getRouteDefinition(group));
|
||||
|
||||
GroupContext.ContextPredicate contextPredicate = new GroupContext.ContextPredicate();
|
||||
contextPredicate.setApiType(ApiType.valueOf(group.getGroupType().toUpperCase(Locale.ROOT)));
|
||||
contextPredicate.setContext(group.getGroupContext());
|
||||
contextPredicate.setNamespace(new GroupContext.ContextNamespace(
|
||||
Position.valueOf(group.getNamespaceNameKeyPosition()
|
||||
.toUpperCase(Locale.ROOT)), group.getNamespaceNameKey()));
|
||||
contextPredicate.setService(new GroupContext.ContextService(
|
||||
Position.valueOf(group.getServiceNameKeyPosition()
|
||||
.toUpperCase(Locale.ROOT)), group.getServiceNameKey()));
|
||||
|
||||
List<GroupContext.ContextSecret> secrets = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(group.getSecretList())) {
|
||||
for (GroupSecret groupSecret : group.getSecretList()) {
|
||||
GroupContext.ContextSecret contextSecret = new GroupContext.ContextSecret();
|
||||
contextSecret.setName(groupSecret.getSecretName());
|
||||
contextSecret.setId(groupSecret.getSecretId());
|
||||
contextSecret.setKey(groupSecret.getSecretKey());
|
||||
contextSecret.setStatus(groupSecret.getStatus());
|
||||
contextSecret.setExpiredTime(groupSecret.getExpiredTime());
|
||||
|
||||
secrets.add(contextSecret);
|
||||
}
|
||||
}
|
||||
|
||||
GroupContext.ContextAuth auth = new GroupContext.ContextAuth();
|
||||
auth.setType(AuthMode.getMode(group.getAuthMode()));
|
||||
auth.setSecrets(secrets);
|
||||
|
||||
|
||||
GroupContext groupContext = new GroupContext();
|
||||
groupContext.setRoutes(new ArrayList<>());
|
||||
groupContext.setPredicate(contextPredicate);
|
||||
groupContext.setAuth(auth);
|
||||
|
||||
groups.put(group.getGroupId(), groupContext);
|
||||
}
|
||||
}
|
||||
|
||||
for (GroupApi groupApi : groupApiResult.getResult()) {
|
||||
GroupContext groupContext = groups.get(groupApi.getGroupId());
|
||||
if (groupContext == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("group api {} not found in group {}", groupApi.getApiId(), groupApi.getGroupId());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
GroupContext.ContextRoute contextRoute = new GroupContext.ContextRoute();
|
||||
contextRoute.setApiId(groupApi.getApiId());
|
||||
contextRoute.setHost(groupApi.getHost());
|
||||
contextRoute.setPath(groupApi.getPath());
|
||||
contextRoute.setPathMapping(groupApi.getPathMapping());
|
||||
contextRoute.setMethod(groupApi.getMethod());
|
||||
contextRoute.setService(groupApi.getServiceName());
|
||||
contextRoute.setNamespaceId(groupApi.getNamespaceId());
|
||||
contextRoute.setNamespace(groupApi.getNamespaceName());
|
||||
if (groupApi.getTimeout() != null) {
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("response-timeout", String.valueOf(groupApi.getTimeout()));
|
||||
contextRoute.setMetadata(metadata);
|
||||
}
|
||||
groupContext.getRoutes().add(contextRoute);
|
||||
}
|
||||
|
||||
if (pathWildcardResult != null && pathWildcardResult.getResult() != null) {
|
||||
for (PathWildcardRule wildcardRule : pathWildcardResult.getResult()) {
|
||||
|
||||
GroupContext.ContextRoute contextRoute = new GroupContext.ContextRoute();
|
||||
contextRoute.setPath(wildcardRule.getWildCardPath());
|
||||
contextRoute.setMethod(wildcardRule.getMethod());
|
||||
contextRoute.setService(wildcardRule.getServiceName());
|
||||
contextRoute.setNamespaceId(wildcardRule.getNamespaceId());
|
||||
contextRoute.setNamespace(wildcardRule.getNamespaceName());
|
||||
if (wildcardRule.getTimeout() != null) {
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("response-timeout", String.valueOf(wildcardRule.getTimeout()));
|
||||
contextRoute.setMetadata(metadata);
|
||||
}
|
||||
|
||||
GroupContext groupContext = groups.get(wildcardRule.getGroupId());
|
||||
groupContext.getRoutes().add(contextRoute);
|
||||
}
|
||||
}
|
||||
|
||||
contextGatewayProperties.setGroups(groups);
|
||||
contextGatewayProperties.setRoutes(routes);
|
||||
contextGatewayProperties.setPathRewrites(Optional.ofNullable(pathRewriteResult.getResult())
|
||||
.orElse(new ArrayList<>()));
|
||||
|
||||
logger.debug("Gateway config loaded. :{}", JacksonUtils.serialize2Json(contextGatewayProperties));
|
||||
|
||||
contextGatewayPropertiesManager.setPathRewrites(contextGatewayProperties.getPathRewrites());
|
||||
|
||||
|
||||
contextGatewayPropertiesManager.refreshGroupRoute(contextGatewayProperties.getGroups());
|
||||
}
|
||||
|
||||
private void saveAsFile(String data, String type) {
|
||||
try {
|
||||
// 写入文件
|
||||
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(getRepoStoreFile(type)));
|
||||
writer.write(data);
|
||||
writer.close();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
logger.warn("[tsf-gateway] save as file occur exception.", t);
|
||||
}
|
||||
}
|
||||
|
||||
private File getRepoStoreFile(String type) {
|
||||
String filePath = GatewayConstant.GATEWAY_REPO_PREFIX + type + GatewayConstant.FILE_SUFFIX;
|
||||
File file = new File(filePath);
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
logger.warn("[tsf-gateway] load group info from local file occur error. filePath: " + filePath, e);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private RouteDefinition getRouteDefinition(Group group) {
|
||||
RouteDefinition routeDefinition = new RouteDefinition();
|
||||
routeDefinition.setUri(URI.create("lb://" + group.getGroupId()));
|
||||
|
||||
PredicateDefinition contextPredicateDefinition = new PredicateDefinition();
|
||||
contextPredicateDefinition.setName("Context");
|
||||
contextPredicateDefinition.setArgs(Collections.singletonMap("group", group.getGroupId()));
|
||||
PredicateDefinition pathPredicateDefinition = new PredicateDefinition();
|
||||
pathPredicateDefinition.setName("Path");
|
||||
pathPredicateDefinition.setArgs(Collections.singletonMap("pattern", group.getGroupContext() + "/**"));
|
||||
routeDefinition.setPredicates(Arrays.asList(contextPredicateDefinition, pathPredicateDefinition));
|
||||
|
||||
FilterDefinition contextFilterDefinition = new FilterDefinition();
|
||||
contextFilterDefinition.setName("Context");
|
||||
contextFilterDefinition.setArgs(Collections.singletonMap("group", group.getGroupId()));
|
||||
routeDefinition.setFilters(Collections.singletonList(contextFilterDefinition));
|
||||
|
||||
routeDefinition.setOrder(-1);
|
||||
|
||||
return routeDefinition;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.cloud.plugin.gateway.context;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.constant.GatewayConstant;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
|
||||
public final class PathRewriteUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PathRewriteUtil.class);
|
||||
private static final String BLOCKED = "Y";
|
||||
|
||||
private PathRewriteUtil() {
|
||||
|
||||
}
|
||||
|
||||
public static String getNewPath(List<PathRewrite> pathRewrites, String path, ServerWebExchange exchange) {
|
||||
String newPath = path;
|
||||
for (PathRewrite pathRewrite : pathRewrites) {
|
||||
String regex = pathRewrite.getRegex();
|
||||
String replacement = pathRewrite.getReplacement();
|
||||
String blockedRegex = replacement.replaceAll("\\$(\\d+|\\{[^/]+?\\})", ".*");
|
||||
|
||||
if (!StringUtils.isBlank(blockedRegex) && BLOCKED.equalsIgnoreCase(pathRewrite.getBlocked())
|
||||
&& path.matches(blockedRegex)) {
|
||||
logger.warn("[TSF-MSGW] uri is blocked by rule. uri: [{}] rule: [{}] -> [{}]",
|
||||
path, regex, replacement);
|
||||
ResponseStatusException exception = new ResponseStatusException(HttpStatus.BAD_REQUEST, "uri is blocked by rule. uri: [" + path + "] rule: [" + regex + "] -> [" + replacement + "]");
|
||||
exchange.getAttributes().put(GatewayConstant.PATH_REWRITE_EXCEPTION, exception);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!StringUtils.isBlank(regex) && !StringUtils.isBlank(replacement) && path.matches(regex)) {
|
||||
newPath = path.replaceAll(regex, replacement);
|
||||
logger.info("[TSF-MSGW] rewrite path [{}] to [{}], rule: [{}] -> [{}]", path, newPath, regex, replacement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Compatible with old versions TSF SDK.
|
||||
*
|
||||
* @author Shedfree Wu
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Component
|
||||
public @interface TsfGatewayFilter {
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/11 23:37
|
||||
*/
|
||||
public enum AuthMode {
|
||||
/**
|
||||
* NONE.
|
||||
*/
|
||||
NONE("none"),
|
||||
/**
|
||||
* SECRET.
|
||||
*/
|
||||
SECRET("secret");
|
||||
|
||||
private final String authMode;
|
||||
|
||||
AuthMode(String authMode) {
|
||||
this.authMode = authMode;
|
||||
}
|
||||
|
||||
public static AuthMode getMode(String authMode) {
|
||||
for (AuthMode groupAuthType : AuthMode.values()) {
|
||||
if (groupAuthType.authMode.equalsIgnoreCase(authMode)) {
|
||||
return groupAuthType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/11 17:05
|
||||
*/
|
||||
public enum CommonStatus {
|
||||
/**
|
||||
* ENABLED.
|
||||
*/
|
||||
ENABLED("enabled"),
|
||||
/**
|
||||
* DISABLED.
|
||||
*/
|
||||
DISABLED("disabled");
|
||||
|
||||
private final String status;
|
||||
|
||||
CommonStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public static CommonStatus getStatus(String status) {
|
||||
for (CommonStatus commonStatus : CommonStatus.values()) {
|
||||
if (commonStatus.status.equals(status)) {
|
||||
return commonStatus;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CommonStatus getStatus(String status, String errorMsg) {
|
||||
for (CommonStatus commonStatus : CommonStatus.values()) {
|
||||
if (commonStatus.status.equals(status)) {
|
||||
return commonStatus;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/10 15:34
|
||||
*/
|
||||
public final class GatewayConstant {
|
||||
/**
|
||||
* CONTEXT_ROUTE.
|
||||
*/
|
||||
public static final String CONTEXT_ROUTE = "contextRoute";
|
||||
/**
|
||||
* 网关能够访问的API分组的缓存文件名称.
|
||||
*/
|
||||
public static final String GROUP_FILE_NAME = "group";
|
||||
/**
|
||||
* 网关能够被访问的API的缓存文件名称.
|
||||
*/
|
||||
public static final String API_FILE_NAME = "api";
|
||||
/**
|
||||
* 网关分组绑定的插件缓存文件名称.
|
||||
*/
|
||||
public static final String PLUGIN_FILE_NAME = "plugin";
|
||||
/**
|
||||
* 网关分组绑定的插件缓存文件名称.
|
||||
*/
|
||||
public static final String PATH_REWRITE_FILE_NAME = "rewrite";
|
||||
/**
|
||||
* PATH_REWRITE_EXCEPTION.
|
||||
*/
|
||||
public static final String PATH_REWRITE_EXCEPTION = "PathRewriteException";
|
||||
/**
|
||||
* 网关路径通配规则缓存文件名称.
|
||||
*/
|
||||
public static final String PATH_WILDCARD_FILE_NAME = "wildcard";
|
||||
/**
|
||||
* 本地文件的文件扩展名称.
|
||||
*/
|
||||
public static final String FILE_SUFFIX = ".json";
|
||||
/**
|
||||
* 网关插件通用部署组名称.
|
||||
*/
|
||||
public static final String GATEWAY_COMMON_DEPLOY_GROUP_ID = "common";
|
||||
/**
|
||||
* 在Spring Cloud Gateway中用来全量匹配所有请求的.
|
||||
*/
|
||||
public static final String GATEWAY_WILDCARD_SERVICE_NAME = "wildcard_tsf_gateway";
|
||||
/**
|
||||
* Tsf Gateway 的限流标签.
|
||||
*/
|
||||
public static final String TSF_GATEWAY_RATELIMIT_CONTEXT_TAG = "tsf-gateway-ratelimit-context";
|
||||
/**
|
||||
* 本地文件的仓库跟目录.
|
||||
*/
|
||||
private static final String GATEWAY_REPO_ROOT = System.getProperty("user.home");
|
||||
/**
|
||||
* Gateway 本地仓库的文件目录.
|
||||
*/
|
||||
public static final String GATEWAY_REPO_PREFIX = GATEWAY_REPO_ROOT + "/tsf/gateway/";
|
||||
|
||||
private GatewayConstant() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
public final class HeaderName {
|
||||
/**
|
||||
* UNIT.
|
||||
*/
|
||||
public static final String UNIT = "TSF-Unit";
|
||||
/**
|
||||
* NAMESPACE_ID.
|
||||
*/
|
||||
public static final String NAMESPACE_ID = "TSF-NamespaceId";
|
||||
/**
|
||||
* APP_KEY.
|
||||
*/
|
||||
public static final String APP_KEY = "x-mg-secretid";
|
||||
/**
|
||||
* ALG.
|
||||
*/
|
||||
public static final String ALG = "x-mg-alg";
|
||||
/**
|
||||
* SIGN.
|
||||
*/
|
||||
public static final String SIGN = "x-mg-sign";
|
||||
/**
|
||||
* NONCE.
|
||||
*/
|
||||
public static final String NONCE = "x-mg-nonce";
|
||||
/**
|
||||
* NODE.
|
||||
*/
|
||||
public static final String NODE = "x-mg-node";
|
||||
/**
|
||||
* TRACE_ID.
|
||||
*/
|
||||
public static final String TRACE_ID = "x-mg-traceid";
|
||||
|
||||
|
||||
private HeaderName() {
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/11 11:54
|
||||
*/
|
||||
public enum HttpMethod {
|
||||
/**
|
||||
* POST.
|
||||
*/
|
||||
POST("POST"),
|
||||
/**
|
||||
* GET.
|
||||
*/
|
||||
GET("GET"),
|
||||
/**
|
||||
* PUT.
|
||||
*/
|
||||
PUT("PUT"),
|
||||
/**
|
||||
* DELETE.
|
||||
*/
|
||||
DELETE("DELETE");
|
||||
|
||||
private final String httpMethod;
|
||||
|
||||
HttpMethod(String httpMethod) {
|
||||
this.httpMethod = httpMethod;
|
||||
}
|
||||
|
||||
public static HttpMethod getHttpMethod(String method) {
|
||||
for (HttpMethod httpMethod : HttpMethod.values()) {
|
||||
if (httpMethod.httpMethod.equalsIgnoreCase(method)) {
|
||||
return httpMethod;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
|
||||
/**
|
||||
* @author: vmershen
|
||||
* @since: 1.1.0
|
||||
**/
|
||||
public final class PluginConstants {
|
||||
/**
|
||||
* 设置每个标签插件JSON串长度.
|
||||
*/
|
||||
public static final Integer TAG_PLUGIN_INFO_LIST_LIMIT = 3000;
|
||||
|
||||
private PluginConstants() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TAG插件traceIdEnabled类型.
|
||||
*/
|
||||
public enum TraceIdEnabledType {
|
||||
/**
|
||||
* Y: enable.
|
||||
*/
|
||||
Y,
|
||||
/**
|
||||
* N: disable.
|
||||
*/
|
||||
N;
|
||||
|
||||
public static TraceIdEnabledType getTraceIdEnabledType(String enabledType) {
|
||||
for (TraceIdEnabledType taskFlowEdgeType : TraceIdEnabledType.values()) {
|
||||
if (taskFlowEdgeType.name().equalsIgnoreCase(enabledType)) {
|
||||
return taskFlowEdgeType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static void checkValidity(String enabledType) {
|
||||
TraceIdEnabledType traceIdEnabledType = getTraceIdEnabledType(enabledType);
|
||||
Optional.ofNullable(traceIdEnabledType).orElseThrow(()
|
||||
-> new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_INVALID, "Tag插件TraceIdEnabled类型"));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
/**
|
||||
* 插件范围类型.
|
||||
* @author seanlxliu
|
||||
* @since 2019/9/10
|
||||
*/
|
||||
public enum PluginScopeType {
|
||||
/**
|
||||
* 绑定组.
|
||||
*/
|
||||
GROUP("group"),
|
||||
|
||||
/**
|
||||
* 绑定API.
|
||||
*/
|
||||
API("api");
|
||||
|
||||
private final String scopeType;
|
||||
|
||||
PluginScopeType(String scopeType) {
|
||||
this.scopeType = scopeType;
|
||||
}
|
||||
|
||||
public static PluginScopeType getScopeType(String scopeType) {
|
||||
for (PluginScopeType pluginScopeType : PluginScopeType.values()) {
|
||||
if (pluginScopeType.scopeType.equals(scopeType)) {
|
||||
return pluginScopeType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getScopeType() {
|
||||
return scopeType;
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.tsf.gateway.core.model.JwtPlugin;
|
||||
import com.tencent.tsf.gateway.core.model.OAuthPlugin;
|
||||
import com.tencent.tsf.gateway.core.model.PluginInfo;
|
||||
import com.tencent.tsf.gateway.core.model.RequestTransformerPlugin;
|
||||
import com.tencent.tsf.gateway.core.model.TagPlugin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public enum PluginType {
|
||||
/**
|
||||
* ReqTransformer 插件实现.
|
||||
*/
|
||||
REQ_TRANSFORMER("ReqTransformer", RequestTransformerPlugin.class),
|
||||
|
||||
/**
|
||||
* OAuth 插件实现.
|
||||
*/
|
||||
OAUTH("OAuth", OAuthPlugin.class),
|
||||
/**
|
||||
* Jwt 插件实现.
|
||||
*/
|
||||
JWT("Jwt", JwtPlugin.class),
|
||||
/**
|
||||
* Tag 转化插件实现.
|
||||
*/
|
||||
TAG("Tag", TagPlugin.class);
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final Map<String, String> pluginMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
pluginMap.put(OAUTH.name(), OAUTH.type);
|
||||
pluginMap.put(JWT.name(), JWT.type);
|
||||
pluginMap.put(TAG.name(), TAG.type);
|
||||
}
|
||||
|
||||
private String type;
|
||||
private Class<? extends PluginInfo> pluginClazz;
|
||||
|
||||
PluginType(String type, Class<? extends PluginInfo> pluginClazz) {
|
||||
this.type = type;
|
||||
this.pluginClazz = pluginClazz;
|
||||
}
|
||||
|
||||
public static PluginType getPluginType(String name) {
|
||||
for (PluginType pluginType : PluginType.values()) {
|
||||
if (pluginType.type.equalsIgnoreCase(name)) {
|
||||
return pluginType;
|
||||
}
|
||||
}
|
||||
logger.warn("Unknown plugin type exception, please upgrade your gateway sdk");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, String> toMap() {
|
||||
return pluginMap;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Class<? extends PluginInfo> getPluginClazz() {
|
||||
return pluginClazz;
|
||||
}
|
||||
|
||||
public void setPluginClazz(Class<? extends PluginInfo> pluginClazz) {
|
||||
this.pluginClazz = pluginClazz;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.constant;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/11 11:42
|
||||
*/
|
||||
public enum TsfAlgType {
|
||||
/**
|
||||
* 0:HMAC_MD5.
|
||||
*/
|
||||
HMAC_MD5("0"),
|
||||
/**
|
||||
* 1:HMAC_SHA_1.
|
||||
*/
|
||||
HMAC_SHA_1("1"),
|
||||
/**
|
||||
* 2:HMAC_SHA_256.
|
||||
*/
|
||||
HMAC_SHA_256("2"),
|
||||
/**
|
||||
* 3:HMAC_SHA_512.
|
||||
*/
|
||||
HMAC_SHA_512("3"),
|
||||
/**
|
||||
* 4:HMAC_SM3.
|
||||
*/
|
||||
HMAC_SM3("4");
|
||||
|
||||
|
||||
private String alg;
|
||||
|
||||
TsfAlgType(String code) {
|
||||
this.alg = code;
|
||||
}
|
||||
|
||||
public static TsfAlgType getSecurityCode(String code) {
|
||||
for (TsfAlgType algType : TsfAlgType.values()) {
|
||||
if (algType.alg.equals(code)) {
|
||||
return algType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAlg() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
public void setAlg(String alg) {
|
||||
this.alg = alg;
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.exception;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/9 13:30
|
||||
*/
|
||||
public enum TsfGatewayError {
|
||||
/**
|
||||
* GATEWAY_INTERNAL_ERROR.
|
||||
*/
|
||||
GATEWAY_INIT_ERROR(5000, "InitializeError: %s", 500),
|
||||
/**
|
||||
* GATEWAY_SYNC_ERROR.
|
||||
*/
|
||||
GATEWAY_SYNC_ERROR(5001, "SyncDataError: %s", 500),
|
||||
/**
|
||||
* GATEWAY_FILE_ERROR.
|
||||
*/
|
||||
GATEWAY_FILE_ERROR(5002, "LocalFile IO Error", 500),
|
||||
/**
|
||||
* GATEWAY_SERIALIZE_ERROR.
|
||||
*/
|
||||
GATEWAY_SERIALIZE_ERROR(5003, "SerializeError: %s", 500),
|
||||
/**
|
||||
* GATEWAY_AUTH_ERROR.
|
||||
*/
|
||||
GATEWAY_AUTH_ERROR(5004, "AuthCheckException: %s", 500),
|
||||
/**
|
||||
* GATEWAY_INTERNAL_ERROR.
|
||||
*/
|
||||
GATEWAY_INTERNAL_ERROR(5005, "Gateway Internal Error: %s", 500),
|
||||
/**
|
||||
* GATEWAY_PARAMETER_REQUIRED.
|
||||
*/
|
||||
GATEWAY_PARAMETER_REQUIRED(5006, "ParameterRequired: %s", 500),
|
||||
/**
|
||||
* GATEWAY_PARAMETER_INVALID.
|
||||
*/
|
||||
GATEWAY_PARAMETER_INVALID(5007, "ParameterInvalid: %s", 500),
|
||||
/**
|
||||
* GATEWAY_BAD_REQUEST.
|
||||
*/
|
||||
GATEWAY_BAD_REQUEST(4000, "BadRequest: %s", 400),
|
||||
/**
|
||||
* GATEWAY_AUTH_FAILED.
|
||||
*/
|
||||
GATEWAY_AUTH_FAILED(4001, "AuthCheckFailed: %s", 401),
|
||||
/**
|
||||
* GATEWAY_REQUEST_FORBIDDEN.
|
||||
*/
|
||||
GATEWAY_REQUEST_FORBIDDEN(4003, "RequestForbidden: %s", 403),
|
||||
/**
|
||||
* GATEWAY_REQUEST_NOT_FOUND.
|
||||
*/
|
||||
GATEWAY_REQUEST_NOT_FOUND(4004, "RequestNotFound: %s", 404),
|
||||
/**
|
||||
* GATEWAY_REQUEST_METHOD_NOT_ALLOWED.
|
||||
*/
|
||||
GATEWAY_REMOTE_REQUEST_INVALID(4016, "RemoteRequestInvalid: %s", 416),
|
||||
/**
|
||||
* GATEWAY_REMOTE_SERVER_AUTH_FAILED.
|
||||
*/
|
||||
GATEWAY_REMOTE_SERVER_AUTH_FAILED(4017, "RemoteServerAuthFailed: %s", 401),
|
||||
/**
|
||||
* GATEWAY_PLUGIN_JWT.
|
||||
*/
|
||||
GATEWAY_PLUGIN_JWT(4020, "JwtError: %s", 500),
|
||||
/**
|
||||
* GATEWAY_REMOTE_SERVER_BUSY.
|
||||
*/
|
||||
GATEWAY_REMOTE_SERVER_BUSY(4021, "Server is busy: %s", 401),
|
||||
/**
|
||||
* GATEWAY_REMOTE_SERVER_CODE_INVALID.
|
||||
*/
|
||||
GATEWAY_REMOTE_SERVER_CODE_INVALID(4022, "Login Code is error: %s", 401),
|
||||
/**
|
||||
* GATEWAY_REMOTE_SERVER_LIMIT.
|
||||
*/
|
||||
GATEWAY_REMOTE_SERVER_LIMIT(4023, "Server Limit : %s", 401),
|
||||
/**
|
||||
* GATEWAY_AUTH_EXPIRED.
|
||||
*/
|
||||
GATEWAY_AUTH_EXPIRED(4024, "AuthCheckExpired : %s", 401),
|
||||
/**
|
||||
* GATEWAY_TOO_MANY_REQUEST.
|
||||
*/
|
||||
GATEWAY_TOO_MANY_REQUEST(4025, "AuthCheckExpired : %s", 429);
|
||||
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String errMsg;
|
||||
|
||||
private Integer httpStatus;
|
||||
|
||||
TsfGatewayError(Integer code, String errMsg, Integer httpStatus) {
|
||||
this.code = code;
|
||||
this.errMsg = errMsg;
|
||||
this.httpStatus = httpStatus;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getErrMsg() {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
public void setErrMsg(String errMsg) {
|
||||
this.errMsg = errMsg;
|
||||
}
|
||||
|
||||
public Integer getHttpStatus() {
|
||||
return httpStatus;
|
||||
}
|
||||
|
||||
public void setHttpStatus(Integer httpStatus) {
|
||||
this.httpStatus = httpStatus;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/9 12:29
|
||||
*/
|
||||
public class TsfGatewayException extends ResponseStatusException {
|
||||
private static final long serialVersionUID = 9210499285923741857L;
|
||||
|
||||
private final TsfGatewayError gatewayError;
|
||||
|
||||
public TsfGatewayException(TsfGatewayError gatewayError, Object... args) {
|
||||
this(gatewayError, null, args);
|
||||
}
|
||||
|
||||
public TsfGatewayException(TsfGatewayError gatewayError, Throwable throwable, Object... args) {
|
||||
super(HttpStatus.resolve(gatewayError.getHttpStatus()), String.format("%s", String.format(gatewayError.getErrMsg(), args)), throwable);
|
||||
this.gatewayError = gatewayError;
|
||||
}
|
||||
|
||||
public TsfGatewayError getGatewayError() {
|
||||
return gatewayError;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.http;
|
||||
|
||||
/**
|
||||
* @ClassName Config
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/8 11:48
|
||||
* @Version 1.0
|
||||
*/
|
||||
public final class HttpConfigConstant {
|
||||
/**
|
||||
* HTTP_CONNECT_TIMEOUT.
|
||||
*/
|
||||
public static final int HTTP_CONNECT_TIMEOUT = 2000;
|
||||
/**
|
||||
* HTTP_SOCKET_TIMEOUT.
|
||||
*/
|
||||
public static final int HTTP_SOCKET_TIMEOUT = 10000;
|
||||
/**
|
||||
* HTTP_MAX_POOL_SIZE.
|
||||
*/
|
||||
public static final int HTTP_MAX_POOL_SIZE = 200;
|
||||
/**
|
||||
* HTTP_MONITOR_INTERVAL.
|
||||
*/
|
||||
public static final int HTTP_MONITOR_INTERVAL = 5000;
|
||||
/**
|
||||
* HTTP_IDLE_TIMEOUT.
|
||||
*/
|
||||
public static final int HTTP_IDLE_TIMEOUT = 30000;
|
||||
|
||||
private HttpConfigConstant() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.polaris.client.util.NamedThreadFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import shade.polaris.org.apache.org.apache.http.HttpEntityEnclosingRequest;
|
||||
import shade.polaris.org.apache.org.apache.http.HttpHost;
|
||||
import shade.polaris.org.apache.org.apache.http.HttpRequest;
|
||||
import shade.polaris.org.apache.org.apache.http.NoHttpResponseException;
|
||||
import shade.polaris.org.apache.org.apache.http.client.HttpRequestRetryHandler;
|
||||
import shade.polaris.org.apache.org.apache.http.client.config.RequestConfig;
|
||||
import shade.polaris.org.apache.org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import shade.polaris.org.apache.org.apache.http.client.methods.HttpGet;
|
||||
import shade.polaris.org.apache.org.apache.http.client.methods.HttpPost;
|
||||
import shade.polaris.org.apache.org.apache.http.client.methods.HttpRequestBase;
|
||||
import shade.polaris.org.apache.org.apache.http.client.protocol.HttpClientContext;
|
||||
import shade.polaris.org.apache.org.apache.http.client.utils.URLEncodedUtils;
|
||||
import shade.polaris.org.apache.org.apache.http.config.Registry;
|
||||
import shade.polaris.org.apache.org.apache.http.config.RegistryBuilder;
|
||||
import shade.polaris.org.apache.org.apache.http.conn.ConnectTimeoutException;
|
||||
import shade.polaris.org.apache.org.apache.http.conn.routing.HttpRoute;
|
||||
import shade.polaris.org.apache.org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import shade.polaris.org.apache.org.apache.http.conn.socket.LayeredConnectionSocketFactory;
|
||||
import shade.polaris.org.apache.org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import shade.polaris.org.apache.org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import shade.polaris.org.apache.org.apache.http.entity.StringEntity;
|
||||
import shade.polaris.org.apache.org.apache.http.impl.client.CloseableHttpClient;
|
||||
import shade.polaris.org.apache.org.apache.http.impl.client.HttpClients;
|
||||
import shade.polaris.org.apache.org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import shade.polaris.org.apache.org.apache.http.message.BasicNameValuePair;
|
||||
import shade.polaris.org.apache.org.apache.http.protocol.HttpContext;
|
||||
import shade.polaris.org.apache.org.apache.http.util.EntityUtils;
|
||||
|
||||
|
||||
/**
|
||||
* @ClassName HttpConnectionPoolUtil
|
||||
* @Description httpclient连接池工具类
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/8 11:56
|
||||
* @Version 1.0
|
||||
*/
|
||||
public final class HttpConnectionPoolUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final int CONNECT_TIMEOUT = HttpConfigConstant.HTTP_CONNECT_TIMEOUT;
|
||||
private static final int SOCKET_TIMEOUT = HttpConfigConstant.HTTP_SOCKET_TIMEOUT;
|
||||
private static final int MAX_CONN = HttpConfigConstant.HTTP_MAX_POOL_SIZE;
|
||||
private static final int MAX_PRE_ROUTE = HttpConfigConstant.HTTP_MAX_POOL_SIZE;
|
||||
private static final int MAX_ROUTE = HttpConfigConstant.HTTP_MAX_POOL_SIZE;
|
||||
private final static Object syncLock = new Object();
|
||||
private volatile static CloseableHttpClient httpClient;
|
||||
private static PoolingHttpClientConnectionManager manager;
|
||||
private static ScheduledExecutorService monitorExecutor;
|
||||
|
||||
//程序退出时,释放资源
|
||||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
closeConnectionPool();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private HttpConnectionPoolUtil() {
|
||||
|
||||
}
|
||||
|
||||
private static void setRequestConfig(HttpRequestBase httpRequestBase, Integer timeout) {
|
||||
RequestConfig requestConfig = RequestConfig
|
||||
.custom()
|
||||
.setConnectionRequestTimeout(timeout == null ? CONNECT_TIMEOUT : timeout)
|
||||
.setConnectTimeout(timeout == null ? CONNECT_TIMEOUT : timeout)
|
||||
.setSocketTimeout(timeout == null ? SOCKET_TIMEOUT : timeout)
|
||||
.build();
|
||||
httpRequestBase.setConfig(requestConfig);
|
||||
}
|
||||
|
||||
public static CloseableHttpClient getHttpClient(String url) {
|
||||
logger.info("url is : {}", url);
|
||||
if (httpClient == null) {
|
||||
//多线程下多个线程同时调用getHttpClient容易导致重复创建httpClient对象的问题,所以加上了同步锁
|
||||
synchronized (syncLock) {
|
||||
if (httpClient == null) {
|
||||
httpClient = createHttpClient(url);
|
||||
//开启监控线程,对异常和空闲线程进行关闭
|
||||
monitorExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("gw-client", true));
|
||||
monitorExecutor.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
//关闭异常连接
|
||||
manager.closeExpiredConnections();
|
||||
//关闭5s空闲的连接
|
||||
manager.closeIdleConnections(HttpConfigConstant.HTTP_IDLE_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||
logger.debug("close expired and idle for over {} ms connection", HttpConfigConstant.HTTP_IDLE_TIMEOUT);
|
||||
}
|
||||
}, HttpConfigConstant.HTTP_MONITOR_INTERVAL, HttpConfigConstant.HTTP_MONITOR_INTERVAL, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public static CloseableHttpClient createHttpClient(String url) {
|
||||
ConnectionSocketFactory plainSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
|
||||
LayeredConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
|
||||
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", plainSocketFactory)
|
||||
.register("https", sslSocketFactory).build();
|
||||
manager = new PoolingHttpClientConnectionManager(registry);
|
||||
//设置连接参数
|
||||
manager.setMaxTotal(MAX_CONN); // 最大连接数
|
||||
manager.setDefaultMaxPerRoute(MAX_PRE_ROUTE); // 路由最大连接数
|
||||
//HttpHost httpHost = new HttpHost(host, port);
|
||||
HttpHost httpHost = new HttpHost(url);
|
||||
manager.setMaxPerRoute(new HttpRoute(httpHost), MAX_ROUTE);
|
||||
//请求失败时,进行请求重试
|
||||
HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
|
||||
@Override
|
||||
public boolean retryRequest(IOException e, int i, HttpContext httpContext) {
|
||||
if (i > 3) {
|
||||
//重试超过3次,放弃请求
|
||||
logger.error("retry has more than 3 time, give up request");
|
||||
return false;
|
||||
}
|
||||
if (e instanceof NoHttpResponseException) {
|
||||
//服务器没有响应,可能是服务器断开了连接,应该重试
|
||||
logger.error("receive no response from server, retry");
|
||||
return true;
|
||||
}
|
||||
if (e instanceof SSLHandshakeException) {
|
||||
// SSL握手异常
|
||||
logger.error("SSL hand shake exception");
|
||||
return false;
|
||||
}
|
||||
if (e instanceof InterruptedIOException) {
|
||||
//超时
|
||||
logger.error("InterruptedIOException");
|
||||
return false;
|
||||
}
|
||||
if (e instanceof UnknownHostException) {
|
||||
// 服务器不可达
|
||||
logger.error("server host unknown");
|
||||
return false;
|
||||
}
|
||||
if (e instanceof ConnectTimeoutException) {
|
||||
// 连接超时
|
||||
logger.error("Connection Time out");
|
||||
return false;
|
||||
}
|
||||
if (e instanceof SSLException) {
|
||||
logger.error("SSLException");
|
||||
return false;
|
||||
}
|
||||
HttpClientContext context = HttpClientContext.adapt(httpContext);
|
||||
HttpRequest request = context.getRequest();
|
||||
//如果请求不是关闭连接的请求
|
||||
return !(request instanceof HttpEntityEnclosingRequest);
|
||||
}
|
||||
};
|
||||
CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).setRetryHandler(handler)
|
||||
.build();
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* get方式,请求参数以?形式拼接在url后面.
|
||||
*
|
||||
* @param url 请求url
|
||||
* @param paramsMap 请求参数
|
||||
* @param headerParamsMap 传入的header参数
|
||||
* @param timeout 单位毫秒
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static String httpGet(String url, Map<String, String> paramsMap, Map<String, String> headerParamsMap, Integer timeout) {
|
||||
// 数据必填项校验
|
||||
if (StringUtils.isEmpty(url)) {
|
||||
throw new IllegalArgumentException("url can not be empty");
|
||||
}
|
||||
CloseableHttpResponse res = null;
|
||||
CloseableHttpClient httpClient = getHttpClient(url);
|
||||
String result = null;
|
||||
String baseUrl = buildUrl(url, paramsMap);
|
||||
logger.info("get request: {}", baseUrl);
|
||||
HttpGet httpGet = new HttpGet(baseUrl);
|
||||
setRequestConfig(httpGet, timeout);
|
||||
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
|
||||
httpGet.setHeader("Accept", "application/json");
|
||||
// 添加传入的header参数
|
||||
buildHeaderParams(httpGet, headerParamsMap);
|
||||
try {
|
||||
res = httpClient.execute(httpGet, HttpClientContext.create());
|
||||
result = EntityUtils.toString(res.getEntity());
|
||||
logger.info("get response :{}", result);
|
||||
if (res.getStatusLine().getStatusCode() != 200) {
|
||||
logger.info("response error: {}", result);
|
||||
throw new IllegalStateException(String.format("call url: %s failed, response: code[%s] body[%s]",
|
||||
baseUrl, res.getStatusLine().getStatusCode(), result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn("Get request failed, url:" + baseUrl, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
closeHttpResponse(res);
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeHttpResponse(CloseableHttpResponse res) {
|
||||
try {
|
||||
if (res != null) {
|
||||
res.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn("Close httpClient failed!", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接池.
|
||||
*/
|
||||
public static void closeConnectionPool() {
|
||||
try {
|
||||
httpClient.close();
|
||||
manager.close();
|
||||
monitorExecutor.shutdown();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String httpPostWithJSON(String url, Map<String, String> paramsMap, String json, Map<String, String> headerParamsMap, Integer timeout)
|
||||
throws Exception {
|
||||
// 数据必填项校验
|
||||
if (StringUtils.isBlank(url)) {
|
||||
throw new Exception("url can't be empty");
|
||||
}
|
||||
// 数据必填项校验
|
||||
if (StringUtils.isBlank(json)) {
|
||||
json = "";
|
||||
}
|
||||
String baseUrl = buildUrl(url, paramsMap);
|
||||
String result = null;
|
||||
CloseableHttpResponse res = null;
|
||||
CloseableHttpClient httpClient = getHttpClient(url);
|
||||
HttpPost httpPost = new HttpPost(baseUrl);
|
||||
setRequestConfig(httpPost, timeout);
|
||||
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
// 添加传入的header参数
|
||||
buildHeaderParams(httpPost, headerParamsMap);
|
||||
|
||||
httpPost.setEntity(new StringEntity(json, StandardCharsets.UTF_8));
|
||||
logger.info("post url: {}", url);
|
||||
try {
|
||||
res = httpClient.execute(httpPost, HttpClientContext.create());
|
||||
result = EntityUtils.toString(res.getEntity());
|
||||
if (res.getStatusLine().getStatusCode() != 200 && res.getStatusLine().getStatusCode() != 201) {
|
||||
logger.info("response error: {}", result);
|
||||
throw new IllegalStateException(String.format("call url: %s failed, response: code[%s] body[%s]",
|
||||
baseUrl, res.getStatusLine().getStatusCode(), result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn("Get request failed, url:" + baseUrl, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
closeHttpResponse(res);
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildUrl(String url, Map<String, String> paramsMap) {
|
||||
String baseUrl = null;
|
||||
if (paramsMap != null && !paramsMap.isEmpty()) {
|
||||
List params = new ArrayList();
|
||||
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (value != null) {
|
||||
params.add(new BasicNameValuePair(key, value));
|
||||
}
|
||||
}
|
||||
if (url.contains("?")) {
|
||||
baseUrl = url + "&" + URLEncodedUtils.format(params, "UTF-8");
|
||||
}
|
||||
else {
|
||||
baseUrl = url + "?" + URLEncodedUtils.format(params, "UTF-8");
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseUrl = url;
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
private static void buildHeaderParams(HttpRequestBase httpRequestBase, Map<String, String> headerParamsMap) {
|
||||
if (null != headerParamsMap) {
|
||||
for (Map.Entry<String, String> entry : headerParamsMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
httpRequestBase.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @ClassName ClaimMapping
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/12 16:12
|
||||
* @Version 1.0
|
||||
*/
|
||||
public class ClaimMapping implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -8768365572845806890L;
|
||||
//参数名称
|
||||
private String parameterName;
|
||||
//映射后参数名称
|
||||
private String mappingParameterName;
|
||||
//映射后参数名称
|
||||
private String location;
|
||||
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
public void setParameterName(String parameterName) {
|
||||
this.parameterName = parameterName;
|
||||
}
|
||||
|
||||
public String getMappingParameterName() {
|
||||
return mappingParameterName;
|
||||
}
|
||||
|
||||
public void setMappingParameterName(String mappingParameterName) {
|
||||
this.mappingParameterName = mappingParameterName;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
|
||||
public class GatewayAllResult {
|
||||
|
||||
private GroupResult groupResult;
|
||||
|
||||
private GroupApiResult groupApiResult;
|
||||
|
||||
private PathRewriteResult pathRewriteResult;
|
||||
|
||||
private PathWildcardResult pathWildcardResult;
|
||||
|
||||
public GatewayAllResult(GroupResult groupResult, GroupApiResult groupApiResult,
|
||||
PathRewriteResult pathRewriteResult, PathWildcardResult pathWildcardResult) {
|
||||
this.groupResult = groupResult;
|
||||
this.groupApiResult = groupApiResult;
|
||||
this.pathRewriteResult = pathRewriteResult;
|
||||
this.pathWildcardResult = pathWildcardResult;
|
||||
}
|
||||
|
||||
public GroupResult getGroupResult() {
|
||||
return groupResult;
|
||||
}
|
||||
|
||||
public void setGroupResult(GroupResult groupResult) {
|
||||
this.groupResult = groupResult;
|
||||
}
|
||||
|
||||
public GroupApiResult getGroupApiResult() {
|
||||
return groupApiResult;
|
||||
}
|
||||
|
||||
public void setGroupApiResult(GroupApiResult groupApiResult) {
|
||||
this.groupApiResult = groupApiResult;
|
||||
}
|
||||
|
||||
public PathRewriteResult getPathRewriteResult() {
|
||||
return pathRewriteResult;
|
||||
}
|
||||
|
||||
public void setPathRewriteResult(PathRewriteResult pathRewriteResult) {
|
||||
this.pathRewriteResult = pathRewriteResult;
|
||||
}
|
||||
|
||||
public PathWildcardResult getPathWildcardResult() {
|
||||
return pathWildcardResult;
|
||||
}
|
||||
|
||||
public void setPathWildcardResult(PathWildcardResult pathWildcardResult) {
|
||||
this.pathWildcardResult = pathWildcardResult;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/10 11:14
|
||||
*/
|
||||
public class GatewayResult<T> implements Serializable {
|
||||
private static final long serialVersionUID = -8391900871963415134L;
|
||||
|
||||
private String gatewayId;
|
||||
|
||||
private String gatewayName;
|
||||
|
||||
private String gatewayGroupId;
|
||||
|
||||
private Integer reversion;
|
||||
|
||||
private String updatedTime;
|
||||
|
||||
private List<T> result;
|
||||
|
||||
public String getGatewayId() {
|
||||
return gatewayId;
|
||||
}
|
||||
|
||||
public void setGatewayId(String gatewayId) {
|
||||
this.gatewayId = gatewayId;
|
||||
}
|
||||
|
||||
public String getGatewayName() {
|
||||
return gatewayName;
|
||||
}
|
||||
|
||||
public void setGatewayName(String gatewayName) {
|
||||
this.gatewayName = gatewayName;
|
||||
}
|
||||
|
||||
public String getGatewayGroupId() {
|
||||
return gatewayGroupId;
|
||||
}
|
||||
|
||||
public void setGatewayGroupId(String gatewayGroupId) {
|
||||
this.gatewayGroupId = gatewayGroupId;
|
||||
}
|
||||
|
||||
public Integer getReversion() {
|
||||
return reversion;
|
||||
}
|
||||
|
||||
public void setReversion(Integer reversion) {
|
||||
this.reversion = reversion;
|
||||
}
|
||||
|
||||
public String getUpdatedTime() {
|
||||
return updatedTime;
|
||||
}
|
||||
|
||||
public void setUpdatedTime(String updatedTime) {
|
||||
this.updatedTime = updatedTime;
|
||||
}
|
||||
|
||||
public List<T> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(List<T> result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/10 10:18
|
||||
*/
|
||||
public class GroupApiResult extends GatewayResult<GroupApi> {
|
||||
private static final long serialVersionUID = -408021255097231992L;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/10 10:17
|
||||
*/
|
||||
public class GroupResult extends GatewayResult<Group> {
|
||||
private static final long serialVersionUID = -7882585922852119178L;
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/4/10 10:18
|
||||
*/
|
||||
public class GroupSecret implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4619764526878050813L;
|
||||
|
||||
|
||||
private String secretId;
|
||||
|
||||
/**
|
||||
* 秘钥值.
|
||||
*/
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 秘钥名称.
|
||||
*/
|
||||
private String secretName;
|
||||
|
||||
/**
|
||||
* API 分组ID.
|
||||
*/
|
||||
private String groupId;
|
||||
|
||||
/**
|
||||
* 启用/禁用.
|
||||
*/
|
||||
private String status;
|
||||
|
||||
|
||||
private String expiredTime;
|
||||
|
||||
|
||||
public String getSecretId() {
|
||||
return secretId;
|
||||
}
|
||||
|
||||
public void setSecretId(String secretId) {
|
||||
this.secretId = secretId;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getSecretName() {
|
||||
return secretName;
|
||||
}
|
||||
|
||||
public void setSecretName(String secretName) {
|
||||
this.secretName = secretName;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getExpiredTime() {
|
||||
return expiredTime;
|
||||
}
|
||||
|
||||
public void setExpiredTime(String expiredTime) {
|
||||
this.expiredTime = expiredTime;
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
|
||||
/**
|
||||
* @ClassName JwtPlugin
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/3 17:15
|
||||
* @Version 1.0
|
||||
*/
|
||||
public class JwtPlugin extends PluginInfo {
|
||||
|
||||
private static final long serialVersionUID = 2238976166882026848L;
|
||||
//公钥对kid
|
||||
private String kid;
|
||||
|
||||
//公钥对
|
||||
private String publicKeyJson;
|
||||
|
||||
//token携带位置
|
||||
private String tokenBaggagePosition;
|
||||
|
||||
//token的key值,校验参数名称
|
||||
private String tokenKeyName;
|
||||
|
||||
//重定向地址,非必填
|
||||
private String redirectUrl;
|
||||
|
||||
//claim参数映射关系json
|
||||
private String claimMappingJson;
|
||||
|
||||
public String getPublicKeyJson() {
|
||||
return publicKeyJson;
|
||||
}
|
||||
|
||||
public void setPublicKeyJson(String publicKeyJson) {
|
||||
this.publicKeyJson = publicKeyJson;
|
||||
}
|
||||
|
||||
public String getTokenBaggagePosition() {
|
||||
return tokenBaggagePosition;
|
||||
}
|
||||
|
||||
public void setTokenBaggagePosition(String tokenBaggagePosition) {
|
||||
this.tokenBaggagePosition = tokenBaggagePosition;
|
||||
}
|
||||
|
||||
public String getTokenKeyName() {
|
||||
return tokenKeyName;
|
||||
}
|
||||
|
||||
public void setTokenKeyName(String tokenKeyName) {
|
||||
this.tokenKeyName = tokenKeyName;
|
||||
}
|
||||
|
||||
public String getRedirectUrl() {
|
||||
return redirectUrl;
|
||||
}
|
||||
|
||||
public void setRedirectUrl(String redirectUrl) {
|
||||
this.redirectUrl = redirectUrl;
|
||||
}
|
||||
|
||||
public String getKid() {
|
||||
return kid;
|
||||
}
|
||||
|
||||
public void setKid(String kid) {
|
||||
this.kid = kid;
|
||||
}
|
||||
|
||||
public String getClaimMappingJson() {
|
||||
return claimMappingJson;
|
||||
}
|
||||
|
||||
public void setClaimMappingJson(String claimMappingJson) {
|
||||
this.claimMappingJson = claimMappingJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public void check() {
|
||||
super.check();
|
||||
if (StringUtils.isEmpty(publicKeyJson)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "publicKeyJson");
|
||||
}
|
||||
if (StringUtils.isEmpty(tokenBaggagePosition) || !(tokenBaggagePosition.equalsIgnoreCase("query") ||
|
||||
tokenBaggagePosition.equalsIgnoreCase("header"))) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "tokenBaggagePosition");
|
||||
}
|
||||
if (StringUtils.isEmpty(tokenKeyName)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "tokenKeyName");
|
||||
}
|
||||
if (StringUtils.isEmpty(kid)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "kid");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @ClassName OAuthResult
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/8 15:51
|
||||
* @Version 1.0
|
||||
*/
|
||||
public class OAuthResult implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 863918261072626284L;
|
||||
private Boolean result;
|
||||
private String payload;
|
||||
|
||||
public Boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Boolean result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(String payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import com.tencent.cloud.plugin.gateway.context.PathRewrite;
|
||||
|
||||
/**
|
||||
* @author seanlxliu
|
||||
* @date 2020/5/19
|
||||
*/
|
||||
public class PathRewriteResult extends GatewayResult<PathRewrite> {
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
/**
|
||||
* @author clarezzhang
|
||||
*/
|
||||
public class PathWildcardResult extends GatewayResult<PathWildcardRule> {
|
||||
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* 路径通配规则.
|
||||
* @author clarezzhang
|
||||
*/
|
||||
public class PathWildcardRule {
|
||||
|
||||
/**
|
||||
* 路径通配规则ID.
|
||||
*/
|
||||
private String wildCardId;
|
||||
|
||||
/**
|
||||
* 网关部署组ID.
|
||||
*/
|
||||
private String groupId;
|
||||
|
||||
/**
|
||||
* 通配路径.
|
||||
*/
|
||||
private String wildCardPath;
|
||||
|
||||
/**
|
||||
* 通配方法.
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 网关微服务ID.
|
||||
*/
|
||||
private String serviceId;
|
||||
|
||||
/**
|
||||
* 网关微服务名称.
|
||||
*/
|
||||
private String serviceName;
|
||||
|
||||
/**
|
||||
* 网关命名空间ID.
|
||||
*/
|
||||
private String namespaceId;
|
||||
|
||||
/**
|
||||
* 网关命名空间名称.
|
||||
*/
|
||||
private String namespaceName;
|
||||
|
||||
/**
|
||||
* 超时时间.
|
||||
*/
|
||||
private Integer timeout;
|
||||
|
||||
/**
|
||||
* 路径通配规则IDs.
|
||||
*/
|
||||
@JsonIgnore
|
||||
private List<String> wildCardIds;
|
||||
|
||||
public String getWildCardId() {
|
||||
return wildCardId;
|
||||
}
|
||||
|
||||
public void setWildCardId(String wildCardId) {
|
||||
this.wildCardId = wildCardId;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public void setServiceId(String serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
public String getNamespaceId() {
|
||||
return namespaceId;
|
||||
}
|
||||
|
||||
public void setNamespaceId(String namespaceId) {
|
||||
this.namespaceId = namespaceId;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
public void setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
public String getNamespaceName() {
|
||||
return namespaceName;
|
||||
}
|
||||
|
||||
public void setNamespaceName(String namespaceName) {
|
||||
this.namespaceName = namespaceName;
|
||||
}
|
||||
|
||||
public String getWildCardPath() {
|
||||
return wildCardPath;
|
||||
}
|
||||
|
||||
public void setWildCardPath(String wildCardPath) {
|
||||
this.wildCardPath = wildCardPath;
|
||||
}
|
||||
|
||||
public List<String> getWildCardIds() {
|
||||
return wildCardIds;
|
||||
}
|
||||
|
||||
public void setWildCardIds(List<String> wildCardIds) {
|
||||
this.wildCardIds = wildCardIds;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public Integer getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(Integer timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathWildcardRule{" +
|
||||
"wildCardId='" + wildCardId + '\'' +
|
||||
", groupId='" + groupId + '\'' +
|
||||
", wildCardPath='" + wildCardPath + '\'' +
|
||||
", method='" + method + '\'' +
|
||||
", serviceId='" + serviceId + '\'' +
|
||||
", serviceName='" + serviceName + '\'' +
|
||||
", namespaceId='" + namespaceId + '\'' +
|
||||
", namespaceName='" + namespaceName + '\'' +
|
||||
", wildCardIds=" + wildCardIds +
|
||||
", timeout=" + timeout +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class PluginArgInfo implements Serializable {
|
||||
private static final long serialVersionUID = -4811191577457792816L;
|
||||
|
||||
//插件参数id
|
||||
private String id;
|
||||
|
||||
//插件id
|
||||
private String pluginId;
|
||||
|
||||
//插件属性名
|
||||
private String key;
|
||||
|
||||
//插件属性值
|
||||
private Object value;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPluginId() {
|
||||
return pluginId;
|
||||
}
|
||||
|
||||
public void setPluginId(String pluginId) {
|
||||
this.pluginId = pluginId;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @ClassName PluginDetail
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/2 11:53
|
||||
* @Version 1.0
|
||||
*/
|
||||
public class PluginDetail extends PluginInfo {
|
||||
|
||||
//插件参数
|
||||
private List<PluginArgInfo> pluginArgInfos;
|
||||
|
||||
public List<PluginArgInfo> getPluginArgInfos() {
|
||||
return pluginArgInfos;
|
||||
}
|
||||
|
||||
public void setPluginArgInfos(List<PluginArgInfo> pluginArgInfos) {
|
||||
this.pluginArgInfos = pluginArgInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof PluginDetail)) {
|
||||
return false;
|
||||
}
|
||||
PluginDetail that = (PluginDetail) o;
|
||||
return Objects.equals(getId(), that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getPluginArgInfos());
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
|
||||
public class PluginInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4823276300296184640L;
|
||||
//网关插件id
|
||||
private String id;
|
||||
|
||||
//插件名称
|
||||
private String name;
|
||||
|
||||
//插件类型
|
||||
private String type;
|
||||
|
||||
//插件执行顺序
|
||||
private Integer order;
|
||||
|
||||
//插件描述
|
||||
private String description;
|
||||
|
||||
private String createdTime;
|
||||
|
||||
private String updatedTime;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
public void setCreatedTime(String createdTime) {
|
||||
this.createdTime = createdTime;
|
||||
}
|
||||
|
||||
public String getUpdatedTime() {
|
||||
return updatedTime;
|
||||
}
|
||||
|
||||
public void setUpdatedTime(String updatedTime) {
|
||||
this.updatedTime = updatedTime;
|
||||
}
|
||||
|
||||
public Integer getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(Integer order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void check() {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "插件名称参数错误");
|
||||
}
|
||||
if (StringUtils.isEmpty(type)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "插件类型参数错误");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginInfo{" +
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", order=" + order +
|
||||
", description='" + description + '\'' +
|
||||
", createdTime='" + createdTime + '\'' +
|
||||
", updatedTime='" + updatedTime + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author vmershen
|
||||
* @date 2019/7/5 10:41
|
||||
*/
|
||||
public class PluginInstanceInfo implements Serializable {
|
||||
private static final long serialVersionUID = -8167195405736835024L;
|
||||
|
||||
/**
|
||||
* API或分组的ID.
|
||||
*/
|
||||
private String scopeValue;
|
||||
|
||||
/**
|
||||
* 插件绑定到的对象类型:group/api.
|
||||
*/
|
||||
private String scopeType;
|
||||
|
||||
//分组绑定的插件列表
|
||||
private List<PluginDetail> pluginDetails;
|
||||
|
||||
public static long getSerialVersionUID() {
|
||||
return serialVersionUID;
|
||||
}
|
||||
|
||||
public String getScopeValue() {
|
||||
return scopeValue;
|
||||
}
|
||||
|
||||
public void setScopeValue(String scopeValue) {
|
||||
this.scopeValue = scopeValue;
|
||||
}
|
||||
|
||||
public List<PluginDetail> getPluginDetails() {
|
||||
return pluginDetails;
|
||||
}
|
||||
|
||||
public void setPluginDetails(List<PluginDetail> pluginDetails) {
|
||||
this.pluginDetails = pluginDetails;
|
||||
}
|
||||
|
||||
public String getScopeType() {
|
||||
return scopeType;
|
||||
}
|
||||
|
||||
public void setScopeType(String scopeType) {
|
||||
this.scopeType = scopeType;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
/**
|
||||
* @author seanlxliu
|
||||
* @since 2019/9/11
|
||||
*/
|
||||
public class PluginInstanceInfoResult extends GatewayResult<PluginInstanceInfo> {
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
|
||||
public class RequestTransformerPlugin extends PluginInfo {
|
||||
|
||||
private static final long serialVersionUID = -2682243185036956532L;
|
||||
|
||||
/**
|
||||
* 参数配置的JSON串.
|
||||
*/
|
||||
private String pluginInfo;
|
||||
|
||||
@JsonIgnore
|
||||
private RequestTransformerPluginInfo requestTransformerPluginInfo;
|
||||
|
||||
public String getPluginInfo() {
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
public void setPluginInfo(String pluginInfo) {
|
||||
this.pluginInfo = pluginInfo;
|
||||
}
|
||||
|
||||
public RequestTransformerPluginInfo getRequestTransformerPluginInfo() {
|
||||
return requestTransformerPluginInfo;
|
||||
}
|
||||
|
||||
public void setRequestTransformerPluginInfo(
|
||||
RequestTransformerPluginInfo requestTransformerPluginInfo) {
|
||||
this.requestTransformerPluginInfo = requestTransformerPluginInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public void check() {
|
||||
super.check();
|
||||
if (StringUtils.isEmpty(pluginInfo)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "验证插件参数");
|
||||
}
|
||||
|
||||
try {
|
||||
requestTransformerPluginInfo = JacksonUtils.deserialize(pluginInfo, new TypeReference<RequestTransformerPluginInfo>() { });
|
||||
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "验证插件格式");
|
||||
}
|
||||
|
||||
int sum = 0;
|
||||
for (TransformerAction action : requestTransformerPluginInfo.getActions()) {
|
||||
if (action.getWeight() == null || action.getWeight() < 0) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED,
|
||||
"权重值不合法:" + action.getWeight());
|
||||
}
|
||||
sum += action.getWeight();
|
||||
}
|
||||
if (sum > 100) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED,
|
||||
"验证插件权重失败,当前权重总和为" + sum);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.constant.PluginConstants;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
import com.tencent.tsf.gateway.core.util.PluginUtil;
|
||||
|
||||
/**
|
||||
* @author seanlxliu
|
||||
* @since 2019/9/12
|
||||
*/
|
||||
public class TagPlugin extends PluginInfo {
|
||||
|
||||
private static final long serialVersionUID = -2682243185036956532L;
|
||||
|
||||
/**
|
||||
* 参数配置的JSON串.
|
||||
*/
|
||||
private String tagPluginInfoList;
|
||||
|
||||
public String getTagPluginInfoList() {
|
||||
return tagPluginInfoList;
|
||||
}
|
||||
|
||||
public void setTagPluginInfoList(String tagPluginInfoList) {
|
||||
this.tagPluginInfoList = tagPluginInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public void check() {
|
||||
super.check();
|
||||
if (StringUtils.isEmpty(tagPluginInfoList)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_REQUIRED, "验证Tag插件参数");
|
||||
}
|
||||
|
||||
if (StringUtils.length(tagPluginInfoList) > PluginConstants.TAG_PLUGIN_INFO_LIST_LIMIT ||
|
||||
!PluginUtil.predicateJsonFormat(tagPluginInfoList)) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_PARAMETER_INVALID, "验证Tag插件参数");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.model;
|
||||
|
||||
import com.tencent.cloud.plugin.gateway.context.Position;
|
||||
import com.tencent.polaris.plugins.connector.consul.service.common.TagCondition;
|
||||
|
||||
public class TransformerTag extends TagCondition {
|
||||
|
||||
private Position tagPosition;
|
||||
|
||||
public Position getTagPosition() {
|
||||
return tagPosition;
|
||||
}
|
||||
|
||||
public void setTagPosition(Position tagPosition) {
|
||||
this.tagPosition = tagPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TransformerTag{" +
|
||||
"tagPosition=" + tagPosition +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.plugin;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @ClassName GatewayPluginContext
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/9 15:44
|
||||
* @Version 1.0
|
||||
*/
|
||||
public class GatewayPluginFactory {
|
||||
|
||||
//根据插件type找对应的插件执行类
|
||||
private static final Map<String, IGatewayPlugin> gatewayPluginExecutorMap = new HashMap<>();
|
||||
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
//获取插件业务执行器
|
||||
public static IGatewayPlugin getGatewayPluginExecutor(String type) {
|
||||
if (StringUtils.isEmpty(type)) {
|
||||
return null;
|
||||
}
|
||||
return gatewayPluginExecutorMap.get(type);
|
||||
}
|
||||
|
||||
public void putGatewayPlugin(String type, IGatewayPlugin gatewayPlugin) {
|
||||
gatewayPluginExecutorMap.put(type, gatewayPlugin);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
logger.info("gatewayPluginExecutorMap start clear");
|
||||
gatewayPluginExecutorMap.clear();
|
||||
logger.info("gatewayPluginExecutorMap clear success");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.plugin;
|
||||
|
||||
import com.tencent.tsf.gateway.core.TsfGatewayRequest;
|
||||
import com.tencent.tsf.gateway.core.model.PluginInfo;
|
||||
import com.tencent.tsf.gateway.core.model.PluginPayload;
|
||||
|
||||
/**
|
||||
* @author vmershen
|
||||
* 2019/7/7 17:08
|
||||
*/
|
||||
public interface IGatewayPlugin<T extends PluginInfo> {
|
||||
|
||||
default PluginPayload invoke(PluginInfo info, TsfGatewayRequest tsfGatewayRequest) {
|
||||
return startUp((T) info, tsfGatewayRequest);
|
||||
}
|
||||
|
||||
PluginPayload startUp(T pluginInfo, TsfGatewayRequest tsfGatewayRequest);
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.plugin;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.cloud.plugin.gateway.context.Position;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.tsf.gateway.core.TsfGatewayRequest;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayError;
|
||||
import com.tencent.tsf.gateway.core.exception.TsfGatewayException;
|
||||
import com.tencent.tsf.gateway.core.model.ClaimMapping;
|
||||
import com.tencent.tsf.gateway.core.model.JwtPlugin;
|
||||
import com.tencent.tsf.gateway.core.model.PluginPayload;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import shade.polaris.org.jose4j.jwa.AlgorithmConstraints;
|
||||
import shade.polaris.org.jose4j.jwk.PublicJsonWebKey;
|
||||
import shade.polaris.org.jose4j.jwt.JwtClaims;
|
||||
import shade.polaris.org.jose4j.jwt.MalformedClaimException;
|
||||
import shade.polaris.org.jose4j.jwt.consumer.InvalidJwtException;
|
||||
import shade.polaris.org.jose4j.jwt.consumer.JwtConsumer;
|
||||
import shade.polaris.org.jose4j.jwt.consumer.JwtConsumerBuilder;
|
||||
import shade.polaris.org.jose4j.lang.JoseException;
|
||||
|
||||
|
||||
/**
|
||||
* @ClassName JwtGatewayPlugin
|
||||
* @Description TODO
|
||||
* @Author vmershen
|
||||
* @Date 2019/7/8 16:45
|
||||
* @Version 1.0
|
||||
*/
|
||||
public class JwtGatewayPlugin implements IGatewayPlugin<JwtPlugin> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Override
|
||||
public PluginPayload startUp(JwtPlugin pluginInfo, TsfGatewayRequest tsfGatewayRequest) {
|
||||
Map<String, String[]> parameterMap = tsfGatewayRequest.getParameterMap();
|
||||
String tokenBaggagePosition = pluginInfo.getTokenBaggagePosition();
|
||||
if (Position.fromString(tokenBaggagePosition) == null) {
|
||||
logger.error("tokenBaggagePosition is wrong, tokenBaggagePosition: {}, tsfGatewayRequest: {}", tokenBaggagePosition, tsfGatewayRequest);
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "tokenBaggagePosition is wrong");
|
||||
}
|
||||
String idToken;
|
||||
if (Position.HEADER.equals(Position.fromString(tokenBaggagePosition))) {
|
||||
idToken = tsfGatewayRequest.getRequestHeader(pluginInfo.getTokenKeyName());
|
||||
}
|
||||
else {
|
||||
//queryParam中取
|
||||
if (parameterMap.get(pluginInfo.getTokenKeyName()) == null || parameterMap.get(pluginInfo.getTokenKeyName()).length == 0) {
|
||||
logger.error("idToken is empty, tsfGatewayRequest: {}", tsfGatewayRequest);
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "idToken is empty");
|
||||
}
|
||||
idToken = parameterMap.get(pluginInfo.getTokenKeyName())[0];
|
||||
}
|
||||
if (StringUtils.isEmpty(idToken)) {
|
||||
logger.error("idToken is empty, tsfGatewayRequest: {}", tsfGatewayRequest);
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_FAILED, "idToken is empty");
|
||||
}
|
||||
|
||||
//获取公钥
|
||||
String publicKeyJson = pluginInfo.getPublicKeyJson();
|
||||
PublicJsonWebKey jwk;
|
||||
//验签
|
||||
try {
|
||||
jwk = PublicJsonWebKey.Factory.newPublicJwk(publicKeyJson);
|
||||
jwk.setKeyId(pluginInfo.getKid());
|
||||
}
|
||||
catch (JoseException e) {
|
||||
logger.error("Generate PublicKey Error", e);
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_ERROR, "Generate PublicKey Error");
|
||||
}
|
||||
//解析idToken, 验签
|
||||
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
|
||||
.setRequireExpirationTime() // the JWT must have an expiration time
|
||||
.setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew
|
||||
.setRequireSubject() // the JWT must have a subject claim
|
||||
.setVerificationKey(jwk.getPublicKey())
|
||||
.setJwsAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, jwk.getAlgorithm()))
|
||||
// ignore audience
|
||||
.setSkipDefaultAudienceValidation()
|
||||
.build(); // create the JwtConsumer instance
|
||||
|
||||
JwtClaims jwtClaims;
|
||||
try {
|
||||
jwtClaims = jwtConsumer.processToClaims(idToken);
|
||||
}
|
||||
catch (InvalidJwtException e) {
|
||||
// Whether or not the JWT has expired being one common reason for invalidity
|
||||
if (e.hasExpired()) {
|
||||
try {
|
||||
long expirationTime = e.getJwtContext()
|
||||
.getJwtClaims()
|
||||
.getExpirationTime()
|
||||
.getValueInMillis();
|
||||
String msg = String
|
||||
.format("JWT expired at (%d)", expirationTime);
|
||||
logger.error(msg);
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_ERROR, msg);
|
||||
}
|
||||
catch (MalformedClaimException e1) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
logger.warn("Invalid JWT! tsfGatewayRequest:{}, error:{}", tsfGatewayRequest, e.getMessage());
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_ERROR, "Invalid JWT");
|
||||
}
|
||||
|
||||
if (jwtClaims == null) {
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_AUTH_ERROR, "Invalid JWT");
|
||||
}
|
||||
|
||||
PluginPayload pluginPayload = new PluginPayload();
|
||||
//若成功,则封装claim字段映射到后台服务
|
||||
if (StringUtils.isNotEmpty(pluginInfo.getClaimMappingJson())) {
|
||||
logger.info("claim json is : " + pluginInfo.getClaimMappingJson());
|
||||
List<ClaimMapping> claimMappings;
|
||||
try {
|
||||
claimMappings = JacksonUtils.deserializeCollection(pluginInfo.getClaimMappingJson(), ClaimMapping.class);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
logger.error("[tsf-gateway] claimMappingJson deserialize data to claimMappings occur exception.", t);
|
||||
throw new TsfGatewayException(TsfGatewayError.GATEWAY_SERIALIZE_ERROR,
|
||||
"claimMappingJson deserialize data to claimMappings occur exception");
|
||||
}
|
||||
|
||||
Map<String, String[]> paramsMap = new HashMap<>();
|
||||
Map<String, String> headerParamsMap = new HashMap<>();
|
||||
for (ClaimMapping claimMapping : claimMappings) {
|
||||
try {
|
||||
String claimValue = jwtClaims.getStringClaimValue(claimMapping.getParameterName());
|
||||
if (!StringUtils.isEmpty(claimValue)) {
|
||||
if (Position.HEADER.equals(Position.fromString(claimMapping.getLocation()))) {
|
||||
headerParamsMap.put(claimMapping.getMappingParameterName(), claimValue);
|
||||
}
|
||||
else if (Position.QUERY.equals(Position.fromString(claimMapping.getLocation()))) {
|
||||
paramsMap.put(claimMapping.getMappingParameterName(), new String[] {claimValue});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MalformedClaimException e) {
|
||||
logger.warn("Claim mapping error, parameterName: " + claimMapping.getParameterName(), e);
|
||||
}
|
||||
}
|
||||
pluginPayload.setRequestHeaders(headerParamsMap);
|
||||
pluginPayload.setParameterMap(paramsMap);
|
||||
}
|
||||
|
||||
return pluginPayload;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.plugin;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.tencent.tsf.gateway.core.TsfGatewayRequest;
|
||||
import com.tencent.tsf.gateway.core.model.PluginPayload;
|
||||
import com.tencent.tsf.gateway.core.model.RequestTransformerPlugin;
|
||||
import com.tencent.tsf.gateway.core.util.PluginUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class ReqTransformerGatewayPlugin implements IGatewayPlugin<RequestTransformerPlugin> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Override
|
||||
public PluginPayload startUp(RequestTransformerPlugin plugin, TsfGatewayRequest tsfGatewayRequest) {
|
||||
PluginPayload payload = new PluginPayload();
|
||||
return PluginUtil.doRequestTransformer(plugin.getRequestTransformerPluginInfo(), tsfGatewayRequest, payload);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.plugin;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.tencent.tsf.gateway.core.TsfGatewayRequest;
|
||||
import com.tencent.tsf.gateway.core.model.PluginPayload;
|
||||
import com.tencent.tsf.gateway.core.model.TagPlugin;
|
||||
import com.tencent.tsf.gateway.core.util.PluginUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author seanlxliu
|
||||
* @since 2019/9/12
|
||||
*/
|
||||
public class TagGatewayPlugin implements IGatewayPlugin<TagPlugin> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public TagGatewayPlugin() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginPayload startUp(TagPlugin tagPlugin, TsfGatewayRequest tsfGatewayRequest) {
|
||||
PluginPayload payload = new PluginPayload();
|
||||
return PluginUtil.transferToTag(tagPlugin.getTagPluginInfoList(), tsfGatewayRequest, payload);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author: vmershen
|
||||
* @description:
|
||||
* @create: 2020-05-23 17:41
|
||||
**/
|
||||
public final class CookieUtil {
|
||||
|
||||
private CookieUtil() {
|
||||
|
||||
}
|
||||
|
||||
public static void buildCookie(StringBuilder cookieStringBuilder, Map<String, String> requestCookieMap) {
|
||||
if (!CollectionUtils.isEmpty(requestCookieMap)) {
|
||||
for (Map.Entry<String, String> cookieEntry : requestCookieMap.entrySet()) {
|
||||
if (cookieStringBuilder.length() == 0) {
|
||||
cookieStringBuilder.append(cookieEntry.getKey() + "=" + cookieEntry.getValue());
|
||||
continue;
|
||||
}
|
||||
cookieStringBuilder.append("; ");
|
||||
cookieStringBuilder.append(cookieEntry.getKey() + "=" + cookieEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import shade.polaris.org.apache.commons.codec.binary.Base64;
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/2/26 16:20
|
||||
*/
|
||||
public final class IdGenerator {
|
||||
|
||||
private IdGenerator() {
|
||||
}
|
||||
|
||||
public static String uuid() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
return uuid.toString();
|
||||
}
|
||||
|
||||
public static String generate() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
return compressedUUID(uuid);
|
||||
}
|
||||
|
||||
public static String generateId(String prefix) {
|
||||
return generateId(prefix, '#');
|
||||
}
|
||||
|
||||
public static String generateId(String prefix, char splitor) {
|
||||
String uuid = generate();
|
||||
return prefix + splitor + uuid;
|
||||
}
|
||||
|
||||
private static String compressedUUID(UUID uuid) {
|
||||
byte[] byUuid = new byte[16];
|
||||
long least = uuid.getLeastSignificantBits();
|
||||
long most = uuid.getMostSignificantBits();
|
||||
long2bytes(most, byUuid, 0);
|
||||
long2bytes(least, byUuid, 8);
|
||||
return Base64.encodeBase64URLSafeString(byUuid);
|
||||
}
|
||||
|
||||
private static void long2bytes(long value, byte[] bytes, int offset) {
|
||||
for (int i = 7; i > -1; --i) {
|
||||
bytes[offset++] = (byte) ((int) (value >> 8 * i & 255L));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String compress(String uuidString) {
|
||||
UUID uuid = UUID.fromString(uuidString);
|
||||
return compressedUUID(uuid);
|
||||
}
|
||||
|
||||
private static String uncompress(String compressedUuid) {
|
||||
if (compressedUuid.length() != 22) {
|
||||
throw new IllegalArgumentException("Invalid uuid!");
|
||||
}
|
||||
else {
|
||||
byte[] byUuid = Base64.decodeBase64(compressedUuid + "==");
|
||||
long most = bytes2long(byUuid, 0);
|
||||
long least = bytes2long(byUuid, 8);
|
||||
UUID uuid = new UUID(most, least);
|
||||
return uuid.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static long bytes2long(byte[] bytes, int offset) {
|
||||
long value = 0L;
|
||||
|
||||
for (int i = 7; i > -1; --i) {
|
||||
value |= ((long) bytes[offset++] & 255L) << 8 * i;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.core.util;
|
||||
|
||||
import com.tencent.tsf.gateway.core.constant.TsfAlgType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import shade.polaris.org.apache.commons.codec.binary.Base64;
|
||||
import shade.polaris.org.apache.commons.codec.digest.HmacUtils;
|
||||
|
||||
|
||||
/**
|
||||
* @author kysonli
|
||||
* 2019/2/26 16:06
|
||||
*/
|
||||
public final class TsfSignUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TsfSignUtil.class);
|
||||
|
||||
|
||||
private TsfSignUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名.
|
||||
*
|
||||
* @param nonce 随机字符串
|
||||
* @param secretId 秘钥ID
|
||||
* @param secretKey 秘钥值
|
||||
* @param algType 签名算法 {@link TsfAlgType}
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static String generate(String nonce, String secretId, String secretKey, TsfAlgType algType) {
|
||||
String digestValue = nonce + secretId + secretKey;
|
||||
byte[] serverSignBytes;
|
||||
switch (algType) {
|
||||
case HMAC_MD5:
|
||||
serverSignBytes = HmacUtils.hmacMd5(secretKey, digestValue);
|
||||
break;
|
||||
case HMAC_SHA_1:
|
||||
serverSignBytes = HmacUtils.hmacSha1(secretKey, digestValue);
|
||||
break;
|
||||
case HMAC_SHA_256:
|
||||
serverSignBytes = HmacUtils.hmacSha256(secretKey, digestValue);
|
||||
break;
|
||||
case HMAC_SHA_512:
|
||||
serverSignBytes = HmacUtils.hmacSha512(secretKey, digestValue);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("不支持的鉴权算法: " + algType);
|
||||
}
|
||||
String signValue = Base64.encodeBase64String(serverSignBytes);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("签名明文:{},签名密文:{}", digestValue, signValue);
|
||||
}
|
||||
return signValue;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||
*
|
||||
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.tsf.gateway.scg;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Compatible with old versions TSF SDK.
|
||||
*
|
||||
* @author Shedfree Wu
|
||||
*/
|
||||
public abstract class AbstractTsfGlobalFilter implements GlobalFilter, Ordered {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
if (shouldFilter(exchange, chain)) {
|
||||
return doFilter(exchange, chain);
|
||||
}
|
||||
else {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public int getOrder();
|
||||
|
||||
abstract public boolean shouldFilter(ServerWebExchange exchange, GatewayFilterChain chain);
|
||||
|
||||
abstract public Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue