Merge branch 'develop' of https://github.com/alibaba/nacos into jraft_naming

This commit is contained in:
chuntaojun 2020-08-19 11:47:11 +08:00
commit f5971e9a17
140 changed files with 2084 additions and 814 deletions

View File

@ -19,7 +19,7 @@
<parent>
<artifactId>nacos-all</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -0,0 +1,43 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.nacos.address.auth;
import com.alibaba.nacos.auth.AuthManager;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.Permission;
import com.alibaba.nacos.auth.model.User;
/**
* Address server auth manager.
*
* <p>For #3091, Only implement an empty auth manager so that address server can startup.</p>
*
* @author xiweng.yy
*/
public class AddressServerAuthManager implements AuthManager {
@Override
public User login(Object request) throws AccessException {
User result = new User();
result.setUserName("nacos");
return result;
}
@Override
public void auth(Permission permission, User user) throws AccessException {
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.nacos.address.configuration;
import com.alibaba.nacos.address.auth.AddressServerAuthManager;
import com.alibaba.nacos.auth.AuthManager;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Address server spring configuration.
*
* @author xiweng.yy
*/
@Configuration
public class AddressServerSpringConfiguration {
@Bean
@ConditionalOnMissingBean(value = AuthManager.class)
public AuthManager getAuthManager() {
return new AddressServerAuthManager();
}
}

View File

@ -19,7 +19,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

83
auth/pom.xml Normal file
View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2018 Alibaba Group Holding Ltd.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-auth</artifactId>
<packaging>jar</packaging>
<name>nacos-auth ${project.version}</name>
<url>http://nacos.io</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -14,12 +14,17 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.Permission;
import com.alibaba.nacos.auth.model.User;
/**
* Access control entry. Can be extended by 3rd party implementations.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public interface AuthManager {

View File

@ -14,8 +14,11 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.annotation;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.auth.parser.DefaultResourceParser;
import com.alibaba.nacos.auth.parser.ResourceParser;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.Retention;
@ -25,6 +28,7 @@ import java.lang.annotation.RetentionPolicy;
* Annotation indicating that the annotated request should be authorized.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
@Retention(RetentionPolicy.RUNTIME)

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.common;
/**
* Resource action type definitions.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public enum ActionTypes {

View File

@ -14,18 +14,16 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.common;
import com.alibaba.nacos.auth.common.env.ReloadableConfigs;
import com.alibaba.nacos.common.JustForTest;
import com.alibaba.nacos.core.env.ReloadableConfigs;
import io.jsonwebtoken.io.Decoders;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Objects;
@ -33,9 +31,9 @@ import java.util.Objects;
* Auth related configurations.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
@Component
@Configuration
public class AuthConfigs {
@ -51,6 +49,11 @@ public class AuthConfigs {
@Value("${nacos.core.auth.default.token.secret.key:}")
private String secretKey;
/**
* secret key byte array.
*/
private byte[] secretKeyBytes;
/**
* Token validity time(seconds).
*/
@ -63,8 +66,11 @@ public class AuthConfigs {
@Value("${nacos.core.auth.system.type:}")
private String nacosAuthSystemType;
public String getSecretKey() {
return secretKey;
public byte[] getSecretKeyBytes() {
if (secretKeyBytes == null) {
secretKeyBytes = Decoders.BASE64.decode(secretKey);
}
return secretKeyBytes;
}
public long getTokenValidityInSeconds() {
@ -107,21 +113,4 @@ public class AuthConfigs {
public static void setCachingEnabled(boolean cachingEnabled) {
AuthConfigs.cachingEnabled = cachingEnabled;
}
@Bean
public FilterRegistrationBean authFilterRegistration() {
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(authFilter());
registration.addUrlPatterns("/*");
registration.setName("authFilter");
registration.setOrder(6);
return registration;
}
@Bean
public AuthFilter authFilter() {
return new AuthFilter();
}
}

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.common;
/**
* Types of all auth implementations.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public enum AuthSystemTypes {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.env;
package com.alibaba.nacos.auth.common.env;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
@ -31,6 +31,7 @@ import java.util.Properties;
* Reload application.properties.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
@Component

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.exception;
import com.alibaba.nacos.api.exception.NacosException;
@ -22,6 +22,7 @@ import com.alibaba.nacos.api.exception.NacosException;
* Exception to be thrown if authorization is failed.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public class AccessException extends NacosException {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.model;
import java.io.Serializable;
@ -22,6 +22,7 @@ import java.io.Serializable;
* Permission to auth.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public class Permission implements Serializable {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.model;
import java.io.Serializable;
@ -22,6 +22,7 @@ import java.io.Serializable;
* Resource used in authorization.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public class Resource implements Serializable {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.model;
import java.io.Serializable;
@ -22,6 +22,7 @@ import java.io.Serializable;
* User information in authorization.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public class User implements Serializable {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.parser;
import org.apache.commons.lang3.StringUtils;
@ -22,6 +22,7 @@ import org.apache.commons.lang3.StringUtils;
* Default resource parser.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public class DefaultResourceParser implements ResourceParser {

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package com.alibaba.nacos.core.auth;
package com.alibaba.nacos.auth.parser;
/**
* Resource parser.
*
* @author nkorange
* @author mai.jh
* @since 1.2.0
*/
public interface ResourceParser {

View File

@ -19,7 +19,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -32,6 +32,7 @@ import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.client.utils.TenantUtil;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -165,6 +166,7 @@ public class ClientWorker implements Closeable {
copy.remove(groupKey);
cacheMap.set(copy);
}
reMakeCacheDataTaskId();
LOGGER.info("[{}] [unsubscribe] {}", this.agent.getName(), groupKey);
MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());
@ -177,11 +179,38 @@ public class ClientWorker implements Closeable {
copy.remove(groupKey);
cacheMap.set(copy);
}
reMakeCacheDataTaskId();
LOGGER.info("[{}] [unsubscribe] {}", agent.getName(), groupKey);
MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());
}
/**
* Remake cacheData taskId.
*/
private void reMakeCacheDataTaskId() {
int listenerSize = cacheMap.get().size();
int remakeTaskId = (int) Math.ceil(listenerSize / ParamUtil.getPerTaskConfigSize());
if (remakeTaskId < (int) currentLongingTaskCount) {
for (int i = 0; i < remakeTaskId; i++) {
int count = 0;
for (String key : cacheMap.get().keySet()) {
if (count == ParamUtil.getPerTaskConfigSize()) {
break;
}
CacheData cacheData = cacheMap.get().get(key);
cacheData.setTaskId(i);
synchronized (cacheMap) {
Map<String, CacheData> copy = new HashMap<String, CacheData>(this.cacheMap.get());
copy.put(key, cacheData);
cacheMap.set(copy);
}
count++;
}
}
}
}
/**
* Add cache data if absent.
*
@ -248,6 +277,8 @@ public class ClientWorker implements Closeable {
cache.setInitializing(true);
} else {
cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group, tenant);
int taskId = cacheMap.get().size() / (int) ParamUtil.getPerTaskConfigSize();
cache.setTaskId(taskId);
// fix issue # 1317
if (enableRemoteSyncConfig) {
String[] ct = getServerConfig(dataId, group, tenant, 3000L);
@ -394,11 +425,16 @@ public class ClientWorker implements Closeable {
int longingTaskCount = (int) Math.ceil(listenerSize / ParamUtil.getPerTaskConfigSize());
if (longingTaskCount > currentLongingTaskCount) {
for (int i = (int) currentLongingTaskCount; i < longingTaskCount; i++) {
taskIdSet.add(i);
// The task list is no order.So it maybe has issues when changing.
executorService.execute(new LongPollingRunnable(i));
}
currentLongingTaskCount = longingTaskCount;
} else if (longingTaskCount < currentLongingTaskCount) {
for (int i = longingTaskCount; i < (int) currentLongingTaskCount; i++) {
taskIdSet.remove(i);
}
}
currentLongingTaskCount = longingTaskCount;
}
/**
@ -656,7 +692,9 @@ public class ClientWorker implements Closeable {
}
inInitializingCacheList.clear();
executorService.execute(this);
if (taskIdSet.contains(taskId)) {
executorService.execute(this);
}
} catch (Throwable e) {
@ -685,6 +723,11 @@ public class ClientWorker implements Closeable {
private final AtomicReference<Map<String, CacheData>> cacheMap = new AtomicReference<Map<String, CacheData>>(
new HashMap<String, CacheData>());
/**
* Store the running taskId.
*/
private final ConcurrentHashSet<Integer> taskIdSet = new ConcurrentHashSet<Integer>();
private final HttpAgent agent;
private final ConfigFilterChainManager configFilterChainManager;

View File

@ -346,7 +346,7 @@ public class ServerListManager implements Closeable {
private List<String> getApacheServerList(String url, String name) {
try {
HttpRestResult<String> httpResult = nacosRestTemplate.get(url, Header.EMPTY, Query.EMPTY, String.class);
if (httpResult.ok()) {
if (DEFAULT_NAME.equals(name)) {
EnvUtil.setSelfEnv(httpResult.getHeader().getOriginalResponseHeader());
@ -367,7 +367,7 @@ public class ServerListManager implements Closeable {
return result;
} else {
LOGGER.error("[check-serverlist] error. addressServerUrl: {}, code: {}", addressServerUrl,
httpResult.getCode());
httpResult.getCode());
return null;
}
} catch (Exception e) {

View File

@ -20,6 +20,7 @@ import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.ThreadUtils;
import org.junit.After;
import org.junit.Assert;
@ -28,7 +29,7 @@ import org.junit.Ignore;
import org.junit.Test;
import java.util.Properties;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;
@Ignore
public class ConfigTest {
@ -36,7 +37,7 @@ public class ConfigTest {
private static ConfigService configService;
@Before
public static void before() throws Exception {
public void before() throws Exception {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
configService = NacosFactory.createConfigService(properties);
@ -48,7 +49,8 @@ public class ConfigTest {
}
@Test
public static void test() throws Exception {
public void test() throws Exception {
// set config
final String dataId = "lessspring";
final String group = "lessspring";
final String content = "lessspring-" + System.currentTimeMillis();
@ -57,24 +59,46 @@ public class ConfigTest {
ThreadUtils.sleep(10000L);
// set change listener
final AtomicBoolean hasListener = new AtomicBoolean(false);
final AtomicBoolean hasChangedCallback = new AtomicBoolean(false);
final String[] changedTmpContent = {""};
String response = configService.getConfigAndSignListener(dataId, group, 5000, new AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.err.println(configInfo);
System.out.println("receiveConfigInfo:" + configInfo);
changedTmpContent[0] = configInfo;
hasChangedCallback.set(true);
}
});
hasListener.set(true);
Assert.assertEquals(content, response);
Scanner scanner = new Scanner(System.in);
System.out.println("input content");
while (scanner.hasNextLine()) {
String s = scanner.next();
if ("exit".equals(s)) {
scanner.close();
return;
// new thread to publish config
final String newRawContent = "nacosnewconfig-" + System.currentTimeMillis();
new Thread(new Runnable() {
@Override
public void run() {
while (hasListener.get()) {
try {
configService.publishConfig(dataId, group, newRawContent);
hasListener.set(false);
break;
} catch (NacosException e) {
e.printStackTrace();
}
}
}
configService.publishConfig(dataId, group, s);
}
}).start();
// spin
do {
if (hasChangedCallback.get()) {
System.out.println(newRawContent + "==> " + changedTmpContent[0]);
Assert.assertEquals(newRawContent, changedTmpContent[0]);
break;
}
} while (!hasChangedCallback.get());
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.nacos.client.config.listener.impl;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
import com.alibaba.nacos.client.config.http.MetricsHttpAgent;
import com.alibaba.nacos.client.config.impl.ClientWorker;
import com.alibaba.nacos.client.utils.ParamUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import static org.mockito.Mockito.mock;
public class ClientWorkerTest {
@Mock
ScheduledExecutorService scheduledExecutorService;
private ClientWorker clientWorker;
private List<Listener> listeners;
private final String dataId = "data";
private final String group = "group";
private final String currentLongingTaskCount = "currentLongingTaskCount";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
clientWorker = new ClientWorker(mock(MetricsHttpAgent.class), mock(ConfigFilterChainManager.class),
mock(Properties.class));
try {
Field executorServiceField = clientWorker.getClass().getDeclaredField("executorService");
executorServiceField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(executorServiceField, executorServiceField.getModifiers() & ~Modifier.FINAL);
executorServiceField.set(clientWorker, scheduledExecutorService);
Listener listener = new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
}
};
listeners = Arrays.asList(listener);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Test
public void testAddLongPollNumberThreads() {
try {
for (int i = 0; i < ParamUtil.getPerTaskConfigSize(); i++) {
clientWorker.addTenantListeners(dataId + i, group, listeners);
}
Field currentLongingTaskCountField = clientWorker.getClass().getDeclaredField(currentLongingTaskCount);
currentLongingTaskCountField.setAccessible(true);
Assert.assertEquals(currentLongingTaskCount, (int) currentLongingTaskCountField.getDouble(clientWorker), 1);
for (int i = (int) ParamUtil.getPerTaskConfigSize(); i < ParamUtil.getPerTaskConfigSize() * 2; i++) {
clientWorker.addTenantListeners(dataId + i, group, listeners);
}
Assert.assertEquals(currentLongingTaskCount, (int) currentLongingTaskCountField.getDouble(clientWorker), 2);
} catch (NacosException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Test
public void testReduceLongPollNumberThreads() {
try {
for (int i = 0; i < ParamUtil.getPerTaskConfigSize() * 3; i++) {
clientWorker.addTenantListeners(dataId + i, group, listeners);
}
Field currentLongingTaskCountField = clientWorker.getClass().getDeclaredField(currentLongingTaskCount);
currentLongingTaskCountField.setAccessible(true);
Assert.assertEquals(currentLongingTaskCount, (int) currentLongingTaskCountField.getDouble(clientWorker), 3);
for (int i = (int) ParamUtil.getPerTaskConfigSize(); i < ParamUtil.getPerTaskConfigSize() * 2; i++) {
clientWorker.removeTenantListener(dataId + i, group, listeners.get(0));
}
Assert.assertEquals(currentLongingTaskCount, (int) currentLongingTaskCountField.getDouble(clientWorker), 2);
} catch (NacosException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}

View File

@ -21,7 +21,7 @@
<parent>
<artifactId>nacos-all</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -21,7 +21,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.common.http;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.handler.ResponseHandler;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
@ -38,7 +39,9 @@ import java.net.URI;
* Base http client.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link com.alibaba.nacos.common.http.client.request.HttpClientRequest}
*/
@Deprecated
public abstract class BaseHttpClient {
protected <T> RestResult<T> execute(CloseableHttpClient httpClient, final Type type, HttpUriRequest request)
@ -79,7 +82,7 @@ public abstract class BaseHttpClient {
@Override
public void cancelled() {
callback.onCancel();
}
});
}
@ -97,19 +100,11 @@ public abstract class BaseHttpClient {
protected HttpRequestBase build(String url, Header header, Object body, String method) throws Exception {
BaseHttpMethod httpMethod = BaseHttpMethod.sourceOf(method);
httpMethod.init(url);
httpMethod.initHeader(header);
httpMethod.initEntity(body, header.getValue("Content-Type"));
return httpMethod.getRequestBase();
}
private Header convertHeader(org.apache.http.Header[] headers) {
final Header nHeader = Header.newInstance();
for (org.apache.http.Header header : headers) {
nHeader.addParam(header.getName(), header.getValue());
}
return nHeader;
final BaseHttpMethod httpMethod = BaseHttpMethod.sourceOf(method);
final HttpRequestBase httpRequestBase = httpMethod.init(url);
HttpUtils.initRequestHeader(httpRequestBase, header);
HttpUtils.initRequestEntity(httpRequestBase, body, header.getValue(HttpHeaderConsts.CONTENT_TYPE));
return httpRequestBase;
}
public static class HttpGetWithEntity extends HttpEntityEnclosingRequestBase {

View File

@ -16,21 +16,9 @@
package com.alibaba.nacos.common.http;
import com.alibaba.nacos.common.http.handler.RequestHandler;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.utils.HttpMethod;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.common.utils.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
@ -39,9 +27,6 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
/**
* Base http method.
@ -139,78 +124,18 @@ public enum BaseHttpMethod {
private String name;
private HttpRequest requestBase;
BaseHttpMethod(String name) {
this.name = name;
}
public void init(String url) {
requestBase = createRequest(url);
public HttpRequestBase init(String url) {
return createRequest(url);
}
protected HttpRequestBase createRequest(String url) {
throw new UnsupportedOperationException();
}
/**
* Init http header.
*
* @param header header
*/
public void initHeader(Header header) {
Iterator<Map.Entry<String, String>> iterator = header.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
requestBase.setHeader(entry.getKey(), entry.getValue());
}
}
/**
* Init http entity.
*
* @param body body
* @param mediaType mediaType {@link ContentType}
* @throws Exception exception
*/
public void initEntity(Object body, String mediaType) throws Exception {
if (body == null) {
return;
}
if (requestBase instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest) requestBase;
ContentType contentType = ContentType.create(mediaType);
StringEntity entity = new StringEntity(RequestHandler.parse(body), contentType);
request.setEntity(entity);
}
}
/**
* Init request from entity map.
*
* @param body body map
* @param charset charset of entity
* @throws Exception exception
*/
public void initFromEntity(Map<String, String> body, String charset) throws Exception {
if (body == null || body.isEmpty()) {
return;
}
List<NameValuePair> params = new ArrayList<NameValuePair>(body.size());
for (Map.Entry<String, String> entry : body.entrySet()) {
params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
if (requestBase instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest) requestBase;
HttpEntity entity = new UrlEncodedFormEntity(params, charset);
request.setEntity(entity);
}
}
public HttpRequestBase getRequestBase() {
return (HttpRequestBase) requestBase;
}
/**
* Value of {@link BaseHttpMethod}.
*

View File

@ -39,4 +39,9 @@ public interface Callback<T> {
*/
void onError(Throwable throwable);
/**
* Callback when the request is cancelled.
*/
void onCancel();
}

View File

@ -30,7 +30,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Use the same HttpClient object in the same space.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link HttpClientBeanHolder}
*/
@Deprecated
public class HttpClientManager {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientManager.class);

View File

@ -16,14 +16,25 @@
package com.alibaba.nacos.common.http;
import com.alibaba.nacos.common.http.handler.RequestHandler;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.utils.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -40,6 +51,63 @@ public final class HttpUtils {
private static final Pattern CONTEXT_PATH_MATCH = Pattern.compile("(\\/)\\1+");
/**
* Init http header.
*
* @param requestBase requestBase {@link HttpRequestBase}
* @param header header
*/
public static void initRequestHeader(HttpRequestBase requestBase, Header header) {
Iterator<Map.Entry<String, String>> iterator = header.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
requestBase.setHeader(entry.getKey(), entry.getValue());
}
}
/**
* Init http entity.
*
* @param requestBase requestBase {@link HttpRequestBase}
* @param body body
* @param mediaType mediaType {@link ContentType}
* @throws Exception exception
*/
public static void initRequestEntity(HttpRequestBase requestBase, Object body, String mediaType) throws Exception {
if (body == null) {
return;
}
if (requestBase instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest) requestBase;
ContentType contentType = ContentType.create(mediaType);
StringEntity entity = new StringEntity(RequestHandler.parse(body), contentType);
request.setEntity(entity);
}
}
/**
* Init request from entity map.
*
* @param requestBase requestBase {@link HttpRequestBase}
* @param body body map
* @param charset charset of entity
* @throws Exception exception
*/
public static void initRequestFromEntity(HttpRequestBase requestBase, Map<String, String> body, String charset) throws Exception {
if (body == null || body.isEmpty()) {
return;
}
List<NameValuePair> params = new ArrayList<NameValuePair>(body.size());
for (Map.Entry<String, String> entry : body.entrySet()) {
params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
if (requestBase instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest) requestBase;
HttpEntity entity = new UrlEncodedFormEntity(params, charset);
request.setEntity(entity);
}
}
/**
* Build URL.
*

View File

@ -25,7 +25,9 @@ import java.lang.reflect.Type;
* Nacos async http client interface.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link com.alibaba.nacos.common.http.client.NacosAsyncRestTemplate}
*/
@Deprecated
@SuppressWarnings("all")
public interface NAsyncHttpClient extends NHttpClient {

View File

@ -22,7 +22,9 @@ import java.io.Closeable;
* Nacos http client interface.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link com.alibaba.nacos.common.http.client.request.HttpClientRequest}
*/
@Deprecated
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public interface NHttpClient extends Closeable {

View File

@ -26,7 +26,9 @@ import java.lang.reflect.Type;
* Nacos sync http client.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link com.alibaba.nacos.common.http.client.NacosRestTemplate}
*/
@Deprecated
@SuppressWarnings("all")
public interface NSyncHttpClient extends NHttpClient {

View File

@ -29,7 +29,9 @@ import java.lang.reflect.Type;
* Nacos async http client.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link com.alibaba.nacos.common.http.client.request.DefaultAsyncHttpClientRequest}
*/
@Deprecated
class NacosAsyncHttpClient extends BaseHttpClient implements NAsyncHttpClient {
private CloseableHttpAsyncClient asyncClient;

View File

@ -30,7 +30,9 @@ import java.lang.reflect.Type;
* Nacos sync http client.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @deprecated Refer to the new {@link com.alibaba.nacos.common.http.client.request.JdkHttpClientRequest}
*/
@Deprecated
class NacosSyncHttpClient extends BaseHttpClient implements NSyncHttpClient {
private CloseableHttpClient client;

View File

@ -61,10 +61,8 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param header http header param
* @param query http query param
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void get(String url, Header header, Query query, Type responseType, Callback<T> callback)
throws Exception {
public <T> void get(String url, Header header, Query query, Type responseType, Callback<T> callback) {
execute(url, HttpMethod.GET, new RequestHttpEntity(header, query), responseType, callback);
}
@ -81,10 +79,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param paramValues paramValues
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void get(String url, Header header, Map<String, String> paramValues, Type responseType,
Callback<T> callback) throws Exception {
Callback<T> callback) {
execute(url, HttpMethod.GET, new RequestHttpEntity(header, Query.newInstance().initParams(paramValues)),
responseType, callback);
}
@ -104,10 +101,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param body get with body
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void getLarge(String url, Header header, Query query, Object body, Type responseType,
Callback<T> callback) throws Exception {
Callback<T> callback) {
execute(url, HttpMethod.GET_LARGE, new RequestHttpEntity(header, query, body), responseType, callback);
}
@ -124,10 +120,8 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param query http query param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void delete(String url, Header header, Query query, Type responseType, Callback<T> callback)
throws Exception {
public <T> void delete(String url, Header header, Query query, Type responseType, Callback<T> callback) {
execute(url, HttpMethod.DELETE, new RequestHttpEntity(header, query), responseType, callback);
}
@ -147,10 +141,8 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param body http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void put(String url, Header header, Query query, Object body, Type responseType, Callback<T> callback)
throws Exception {
public <T> void put(String url, Header header, Query query, Object body, Type responseType, Callback<T> callback) {
execute(url, HttpMethod.PUT, new RequestHttpEntity(header, query, body), responseType, callback);
}
@ -171,10 +163,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param body http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void putJson(String url, Header header, Map<String, String> paramValues, String body, Type responseType,
Callback<T> callback) throws Exception {
Callback<T> callback) {
execute(url, HttpMethod.PUT, new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_JSON),
Query.newInstance().initParams(paramValues), body), responseType, callback);
}
@ -196,10 +187,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param bodyValues http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void putForm(String url, Header header, Query query, Map<String, String> bodyValues, Type responseType,
Callback<T> callback) throws Exception {
Callback<T> callback) {
execute(url, HttpMethod.PUT,
new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED), query, bodyValues),
responseType, callback);
@ -222,10 +212,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param bodyValues http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void putForm(String url, Header header, Map<String, String> paramValues, Map<String, String> bodyValues,
Type responseType, Callback<T> callback) throws Exception {
Type responseType, Callback<T> callback) {
execute(url, HttpMethod.PUT, new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),
Query.newInstance().initParams(paramValues), bodyValues), responseType, callback);
}
@ -246,10 +235,8 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param body http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void post(String url, Header header, Query query, Object body, Type responseType, Callback<T> callback)
throws Exception {
public <T> void post(String url, Header header, Query query, Object body, Type responseType, Callback<T> callback) {
execute(url, HttpMethod.POST, new RequestHttpEntity(header, query, body), responseType, callback);
}
@ -270,10 +257,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param body http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void postJson(String url, Header header, Map<String, String> paramValues, String body, Type responseType,
Callback<T> callback) throws Exception {
Callback<T> callback) {
execute(url, HttpMethod.POST, new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_JSON),
Query.newInstance().initParams(paramValues), body), responseType, callback);
}
@ -295,10 +281,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param bodyValues http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void postForm(String url, Header header, Query query, Map<String, String> bodyValues, Type responseType,
Callback<T> callback) throws Exception {
Callback<T> callback) {
execute(url, HttpMethod.POST,
new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED), query, bodyValues),
responseType, callback);
@ -321,10 +306,9 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
* @param bodyValues http body param
* @param responseType return type
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void postForm(String url, Header header, Map<String, String> paramValues, Map<String, String> bodyValues,
Type responseType, Callback<T> callback) throws Exception {
Type responseType, Callback<T> callback) {
execute(url, HttpMethod.POST,
new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),
Query.newInstance().initParams(paramValues), bodyValues), responseType, callback);
@ -333,13 +317,18 @@ public class NacosAsyncRestTemplate extends AbstractNacosRestTemplate {
@SuppressWarnings("unchecked")
private <T> void execute(String url, String httpMethod, RequestHttpEntity requestEntity, Type type,
Callback<T> callback) throws Exception {
URI uri = HttpUtils.buildUri(url, requestEntity.getQuery());
if (logger.isDebugEnabled()) {
logger.debug("HTTP method: {}, url: {}, body: {}", httpMethod, uri, requestEntity.getBody());
Callback<T> callback) {
try {
URI uri = HttpUtils.buildUri(url, requestEntity.getQuery());
if (logger.isDebugEnabled()) {
logger.debug("HTTP method: {}, url: {}, body: {}", httpMethod, uri, requestEntity.getBody());
}
ResponseHandler<T> responseHandler = super.selectResponseHandler(type);
clientRequest.execute(uri, httpMethod, requestEntity, responseHandler, callback);
} catch (Exception e) {
// When an exception occurs, use Callback to pass it instead of throw it directly.
callback.onError(e);
}
ResponseHandler<T> responseHandler = super.selectResponseHandler(type);
clientRequest.execute(uri, httpMethod, requestEntity, responseHandler, callback);
}
/**

View File

@ -68,7 +68,7 @@ public class DefaultAsyncHttpClientRequest implements AsyncHttpClientRequest {
@Override
public void cancelled() {
callback.onCancel();
}
});

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.common.http.client.request;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.BaseHttpMethod;
import com.alibaba.nacos.common.http.HttpClientConfig;
import com.alibaba.nacos.common.http.HttpUtils;
import com.alibaba.nacos.common.http.client.response.DefaultClientHttpResponse;
import com.alibaba.nacos.common.http.client.response.HttpClientResponse;
import com.alibaba.nacos.common.http.param.Header;
@ -56,19 +57,18 @@ public class DefaultHttpClientRequest implements HttpClientRequest {
}
static HttpRequestBase build(URI uri, String method, RequestHttpEntity requestHttpEntity) throws Exception {
Header headers = requestHttpEntity.getHeaders();
BaseHttpMethod httpMethod = BaseHttpMethod.sourceOf(method);
httpMethod.init(uri.toString());
httpMethod.initHeader(headers);
final Header headers = requestHttpEntity.getHeaders();
final BaseHttpMethod httpMethod = BaseHttpMethod.sourceOf(method);
final HttpRequestBase httpRequestBase = httpMethod.init(uri.toString());
HttpUtils.initRequestHeader(httpRequestBase, headers);
if (MediaType.APPLICATION_FORM_URLENCODED.equals(headers.getValue(HttpHeaderConsts.CONTENT_TYPE))
&& requestHttpEntity.getBody() instanceof Map) {
httpMethod.initFromEntity((Map<String, String>) requestHttpEntity.getBody(), headers.getCharset());
HttpUtils.initRequestFromEntity(httpRequestBase, (Map<String, String>) requestHttpEntity.getBody(), headers.getCharset());
} else {
httpMethod.initEntity(requestHttpEntity.getBody(), headers.getValue(HttpHeaderConsts.CONTENT_TYPE));
HttpUtils.initRequestEntity(httpRequestBase, requestHttpEntity.getBody(), headers.getValue(HttpHeaderConsts.CONTENT_TYPE));
}
HttpRequestBase requestBase = httpMethod.getRequestBase();
replaceDefaultConfig(requestBase, requestHttpEntity.getHttpClientConfig());
return requestBase;
replaceDefaultConfig(httpRequestBase, requestHttpEntity.getHttpClientConfig());
return httpRequestBase;
}
/**

View File

@ -44,6 +44,6 @@ public final class MediaType {
public static final String TEXT_HTML = "text/html";
public static final String TEXT_PLAIN = "text/xml";
public static final String TEXT_PLAIN = "text/plain";
}

View File

@ -20,7 +20,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -16,11 +16,10 @@
package com.alibaba.nacos.config.server.auth;
import com.alibaba.nacos.core.auth.Resource;
import com.alibaba.nacos.core.auth.ResourceParser;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.nacos.auth.model.Resource;
import com.alibaba.nacos.auth.parser.ResourceParser;
import org.apache.commons.lang3.StringUtils;
/**

View File

@ -28,6 +28,7 @@ import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.ROLE_INFO_ROW_MAPPER;
@ -134,4 +135,11 @@ public class EmbeddedRolePersistServiceImpl implements RolePersistService {
}
}
@Override
public List<String> findRolesLikeRoleName(String role) {
String sql = "SELECT role FROM roles WHERE role like ? ";
List<String> users = databaseOperate.queryMany(sql, new String[] {"%" + role + "%"}, String.class);
return users;
}
}

View File

@ -28,6 +28,7 @@ import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.USER_ROW_MAPPER;
@ -117,4 +118,11 @@ public class EmbeddedUserPersistServiceImpl implements UserPersistService {
}
return pageInfo;
}
@Override
public List<String> findUserLikeUsername(String username) {
String sql = "SELECT username FROM users WHERE username like ? ";
List<String> users = databaseOperate.queryMany(sql, new String[] {"%" + username + "%"}, String.class);
return users;
}
}

View File

@ -33,6 +33,7 @@ import javax.annotation.PostConstruct;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.ROLE_INFO_ROW_MAPPER;
@ -152,6 +153,13 @@ public class ExternalRolePersistServiceImpl implements RolePersistService {
}
}
@Override
public List<String> findRolesLikeRoleName(String role) {
String sql = "SELECT role FROM roles WHERE role like '%' ? '%'";
List<String> users = this.jt.queryForList(sql, new String[]{role}, String.class);
return users;
}
private static final class RoleInfoRowMapper implements RowMapper<RoleInfo> {
@Override

View File

@ -31,6 +31,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.USER_ROW_MAPPER;
@ -145,4 +146,11 @@ public class ExternalUserPersistServiceImpl implements UserPersistService {
throw e;
}
}
@Override
public List<String> findUserLikeUsername(String username) {
String sql = "SELECT username FROM users WHERE username like '%' ? '%'";
List<String> users = this.jt.queryForList(sql, new String[]{username}, String.class);
return users;
}
}

View File

@ -18,6 +18,8 @@ package com.alibaba.nacos.config.server.auth;
import com.alibaba.nacos.config.server.model.Page;
import java.util.List;
/**
* Role CRUD service.
*
@ -37,4 +39,5 @@ public interface RolePersistService {
void deleteRole(String role, String username);
List<String> findRolesLikeRoleName(String role);
}

View File

@ -19,6 +19,8 @@ package com.alibaba.nacos.config.server.auth;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.User;
import java.util.List;
/**
* User CRUD service.
*
@ -37,5 +39,7 @@ public interface UserPersistService {
User findUserByUsername(String username);
Page<User> getUsers(int pageNo, int pageSize);
List<String> findUserLikeUsername(String username);
}

View File

@ -17,6 +17,8 @@
package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.utils.MapUtils;
import com.alibaba.nacos.config.server.auth.ConfigResourceParser;
@ -43,8 +45,6 @@ import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.config.server.utils.TimeUtils;
import com.alibaba.nacos.config.server.utils.ZipUtils;
import com.alibaba.nacos.core.auth.ActionTypes;
import com.alibaba.nacos.core.auth.Secured;
import com.alibaba.nacos.core.utils.InetUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
@ -134,6 +134,7 @@ public class ConfigController {
final String srcIp = RequestUtil.getRemoteIp(request);
final String requestIpApp = RequestUtil.getAppName(request);
srcUser = RequestUtil.getSrcUserName(request);
// check tenant
ParamUtils.checkTenant(tenant);
ParamUtils.checkParam(dataId, group, "datumId", content);
@ -183,8 +184,8 @@ public class ConfigController {
* Get configure board infomation fail.
*
* @throws ServletException ServletException.
* @throws IOException IOException.
* @throws NacosException NacosException.
* @throws IOException IOException.
* @throws NacosException NacosException.
*/
@GetMapping
@Secured(action = ActionTypes.READ, parser = ConfigResourceParser.class)
@ -239,10 +240,11 @@ public class ConfigController {
ParamUtils.checkParam(dataId, group, "datumId", "rm");
ParamUtils.checkParam(tag);
String clientIp = RequestUtil.getRemoteIp(request);
String srcUser = RequestUtil.getSrcUserName(request);
if (StringUtils.isBlank(tag)) {
persistService.removeConfigInfo(dataId, group, tenant, clientIp, null);
persistService.removeConfigInfo(dataId, group, tenant, clientIp, srcUser);
} else {
persistService.removeConfigInfoTag(dataId, group, tenant, tag, clientIp, null);
persistService.removeConfigInfoTag(dataId, group, tenant, tag, clientIp, srcUser);
}
final Timestamp time = TimeUtils.getCurrentTime();
ConfigTraceService.logPersistenceEvent(dataId, group, tenant, null, time.getTime(), clientIp,
@ -394,7 +396,7 @@ public class ConfigController {
* Execute to remove beta operation.
*
* @param dataId dataId string value.
* @param group group string value.
* @param group group string value.
* @param tenant tenant string value.
* @return Execute to operate result.
*/
@ -425,7 +427,7 @@ public class ConfigController {
* Execute to query beta operation.
*
* @param dataId dataId string value.
* @param group group string value.
* @param group group string value.
* @param tenant tenant string value.
* @return RestResult for ConfigInfo4Beta.
*/
@ -452,11 +454,11 @@ public class ConfigController {
/**
* Execute export config operation.
*
* @param dataId dataId string value.
* @param group group string value.
* @param dataId dataId string value.
* @param group group string value.
* @param appName appName string value.
* @param tenant tenant string value.
* @param ids id list value.
* @param tenant tenant string value.
* @param ids id list value.
* @return ResponseEntity.
*/
@GetMapping(params = "export=true")
@ -504,11 +506,11 @@ public class ConfigController {
/**
* Execute import and publish config operation.
*
* @param request http servlet request .
* @param srcUser src user string value.
* @param request http servlet request .
* @param srcUser src user string value.
* @param namespace namespace string value.
* @param policy policy model.
* @param file MultipartFile.
* @param policy policy model.
* @param file MultipartFile.
* @return RestResult Map.
* @throws NacosException NacosException.
*/
@ -605,11 +607,11 @@ public class ConfigController {
/**
* Execute clone config operation.
*
* @param request http servlet request .
* @param srcUser src user string value.
* @param namespace namespace string value.
* @param request http servlet request .
* @param srcUser src user string value.
* @param namespace namespace string value.
* @param configBeansList config beans list.
* @param policy config policy model.
* @param policy config policy model.
* @return RestResult for map.
* @throws NacosException NacosException.
*/

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.Objects;
@ -29,8 +31,6 @@ import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.repository.embedded.DatabaseOperate;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.config.server.utils.PropertyUtil;
import com.alibaba.nacos.core.auth.ActionTypes;
import com.alibaba.nacos.core.auth.Secured;
import com.alibaba.nacos.core.utils.ApplicationUtils;
import com.alibaba.nacos.core.utils.WebUtils;
import org.apache.commons.lang3.StringUtils;

View File

@ -16,7 +16,9 @@
package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.enums.FileTypeEnum;
import com.alibaba.nacos.config.server.model.CacheItem;
import com.alibaba.nacos.config.server.model.ConfigInfoBase;
import com.alibaba.nacos.config.server.service.ConfigCacheService;
@ -136,8 +138,18 @@ public class ConfigServletInner {
isBeta = true;
}
}
String configType = cacheItem.getType();
response.setHeader("Config-Type", (null != configType) ? configType : "text");
final String configType =
(null != cacheItem.getType()) ? cacheItem.getType() : FileTypeEnum.TEXT.getFileType();
response.setHeader("Config-Type", configType);
String contentTypeHeader;
try {
contentTypeHeader = FileTypeEnum.valueOf(configType.toUpperCase()).getContentType();
} catch (IllegalArgumentException ex) {
contentTypeHeader = FileTypeEnum.TEXT.getContentType();
}
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, contentTypeHeader);
}
File file = null;
ConfigInfoBase configInfoBase = null;

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.config.server.enums;
import com.alibaba.nacos.common.http.param.MediaType;
/**
* Config file type enum.
*
@ -27,58 +29,73 @@ public enum FileTypeEnum {
/**
* Yaml file.
*/
YML("yaml"),
YML("yaml", MediaType.TEXT_PLAIN),
/**
* Yaml file.
*/
YAML("yaml"),
YAML("yaml", MediaType.TEXT_PLAIN),
/**
* Text file.
*/
TXT("text"),
TXT("text", MediaType.TEXT_PLAIN),
/**
* Text file.
*/
TEXT("text"),
TEXT("text", MediaType.TEXT_PLAIN),
/**
* Json file.
*/
JSON("json"),
JSON("json", MediaType.APPLICATION_JSON),
/**
* Xml file.
*/
XML("xml"),
XML("xml", MediaType.APPLICATION_XML),
/**
* Html file.
*/
HTM("html"),
HTM("html", MediaType.TEXT_HTML),
/**
* Html file.
*/
HTML("html"),
HTML("html", MediaType.TEXT_HTML),
/**
* Properties file.
*/
PROPERTIES("properties");
PROPERTIES("properties", MediaType.TEXT_PLAIN);
/**
* File type corresponding to file extension.
*/
private String fileType;
/**
* Http Content type corresponding to file extension.
*/
private String contentType;
FileTypeEnum(String fileType) {
this.fileType = fileType;
this.contentType = MediaType.TEXT_PLAIN;
}
FileTypeEnum(String fileType, String contentType) {
this.fileType = fileType;
this.contentType = contentType;
}
public String getFileType() {
return this.fileType;
}
public String getContentType() {
return contentType;
}
}

View File

@ -16,8 +16,8 @@
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.config.server.model.AclInfo;
import com.alibaba.nacos.config.server.utils.JSONUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -76,7 +76,7 @@ public class ClientIpWhiteList {
}
DEFAULT_LOG.warn("[clientIpWhiteList] {}", content);
try {
AclInfo acl = (AclInfo) JSONUtils.deserializeObject(content, AclInfo.class);
AclInfo acl = JacksonUtils.toObj(content, AclInfo.class);
isOpen = acl.getIsOpen();
CLIENT_IP_WHITELIST.set(acl.getIps());
} catch (Exception ioe) {

View File

@ -16,21 +16,20 @@
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.SampleResult;
import com.alibaba.nacos.config.server.service.notify.NotifyService;
import com.alibaba.nacos.config.server.utils.ConfigExecutor;
import com.alibaba.nacos.config.server.utils.JSONUtils;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.utils.ApplicationUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
@ -178,19 +177,15 @@ public class ConfigSubService {
}
String urlAll = getUrl(ip, url) + "?" + paramUrl;
com.alibaba.nacos.config.server.service.notify.NotifyService.HttpResult result = NotifyService
RestResult<String> result = NotifyService
.invokeURL(urlAll, null, Constants.ENCODE);
// Http code 200
if (result.code == HttpURLConnection.HTTP_OK) {
String json = result.content;
SampleResult resultObj = JSONUtils.deserializeObject(json, new TypeReference<SampleResult>() {
});
return resultObj;
if (result.ok()) {
return JacksonUtils.toObj(result.getData(), SampleResult.class);
} else {
LogUtil.DEFAULT_LOG.info("Can not get clientInfo from {} with {}", ip, result.code);
LogUtil.DEFAULT_LOG.info("Can not get clientInfo from {} with {}", ip, result.getData());
return null;
}
} catch (Exception e) {

View File

@ -16,6 +16,11 @@
package com.alibaba.nacos.config.server.service.notify;
import com.alibaba.nacos.common.http.Callback;
import com.alibaba.nacos.common.http.client.NacosAsyncRestTemplate;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.Subscriber;
@ -25,20 +30,11 @@ import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
import com.alibaba.nacos.config.server.utils.ConfigExecutor;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.config.server.utils.PropertyUtil;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.utils.ApplicationUtils;
import com.alibaba.nacos.core.utils.InetUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -63,7 +59,6 @@ public class AsyncNotifyService {
@Autowired
public AsyncNotifyService(ServerMemberManager memberManager) {
this.memberManager = memberManager;
httpclient.start();
// Register ConfigDataChangeEvent to NotifyCenter.
NotifyCenter.registerToPublisher(ConfigDataChangeEvent.class, NotifyCenter.ringBufferSize);
@ -89,7 +84,7 @@ public class AsyncNotifyService {
queue.add(new NotifySingleTask(dataId, group, tenant, tag, dumpTs, member.getAddress(),
evt.isBeta));
}
ConfigExecutor.executeAsyncNotify(new AsyncTask(httpclient, queue));
ConfigExecutor.executeAsyncNotify(new AsyncTask(nacosAsyncRestTemplate, queue));
}
}
@ -100,12 +95,7 @@ public class AsyncNotifyService {
});
}
private RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(PropertyUtil.getNotifyConnectTimeout())
.setSocketTimeout(PropertyUtil.getNotifySocketTimeout()).build();
private CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig)
.build();
private final NacosAsyncRestTemplate nacosAsyncRestTemplate = HttpClientManager.getNacosAsyncRestTemplate();
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncNotifyService.class);
@ -113,8 +103,12 @@ public class AsyncNotifyService {
class AsyncTask implements Runnable {
public AsyncTask(CloseableHttpAsyncClient httpclient, Queue<NotifySingleTask> queue) {
this.httpclient = httpclient;
private Queue<NotifySingleTask> queue;
private NacosAsyncRestTemplate restTemplate;
public AsyncTask(NacosAsyncRestTemplate restTemplate, Queue<NotifySingleTask> queue) {
this.restTemplate = restTemplate;
this.queue = queue;
}
@ -138,52 +132,47 @@ public class AsyncNotifyService {
// get delay time and set fail count to the task
asyncTaskExecute(task);
} else {
HttpGet request = new HttpGet(task.url);
request.setHeader(NotifyService.NOTIFY_HEADER_LAST_MODIFIED,
String.valueOf(task.getLastModified()));
request.setHeader(NotifyService.NOTIFY_HEADER_OP_HANDLE_IP, InetUtils.getSelfIp());
Header header = Header.newInstance();
header.addParam(NotifyService.NOTIFY_HEADER_LAST_MODIFIED, String.valueOf(task.getLastModified()));
header.addParam(NotifyService.NOTIFY_HEADER_OP_HANDLE_IP, InetUtils.getSelfIp());
if (task.isBeta) {
request.setHeader("isBeta", "true");
header.addParam("isBeta", "true");
}
httpclient.execute(request, new AsyncNotifyCallBack(httpclient, task));
restTemplate.get(task.url, header, Query.EMPTY, String.class, new AsyncNotifyCallBack(task));
}
}
}
}
private Queue<NotifySingleTask> queue;
private CloseableHttpAsyncClient httpclient;
}
private void asyncTaskExecute(NotifySingleTask task) {
int delay = getDelayTime(task);
Queue<NotifySingleTask> queue = new LinkedList<NotifySingleTask>();
queue.add(task);
AsyncTask asyncTask = new AsyncTask(httpclient, queue);
AsyncTask asyncTask = new AsyncTask(nacosAsyncRestTemplate, queue);
ConfigExecutor.scheduleAsyncNotify(asyncTask, delay, TimeUnit.MILLISECONDS);
}
class AsyncNotifyCallBack implements FutureCallback<HttpResponse> {
class AsyncNotifyCallBack implements Callback<String> {
private NotifySingleTask task;
public AsyncNotifyCallBack(CloseableHttpAsyncClient httpClient, NotifySingleTask task) {
public AsyncNotifyCallBack(NotifySingleTask task) {
this.task = task;
this.httpClient = httpClient;
}
@Override
public void completed(HttpResponse response) {
public void onReceive(RestResult<String> result) {
long delayed = System.currentTimeMillis() - task.getLastModified();
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
if (result.ok()) {
ConfigTraceService.logNotifyEvent(task.getDataId(), task.getGroup(), task.getTenant(), null,
task.getLastModified(), InetUtils.getSelfIp(), ConfigTraceService.NOTIFY_EVENT_OK, delayed,
task.target);
} else {
LOGGER.error("[notify-error] target:{} dataId:{} group:{} ts:{} code:{}", task.target, task.getDataId(),
task.getGroup(), task.getLastModified(), response.getStatusLine().getStatusCode());
task.getGroup(), task.getLastModified(), result.getCode());
ConfigTraceService.logNotifyEvent(task.getDataId(), task.getGroup(), task.getTenant(), null,
task.getLastModified(), InetUtils.getSelfIp(), ConfigTraceService.NOTIFY_EVENT_ERROR, delayed,
task.target);
@ -197,11 +186,10 @@ public class AsyncNotifyService {
MetricsMonitor.getConfigNotifyException().increment();
}
HttpClientUtils.closeQuietly(response);
}
@Override
public void failed(Exception ex) {
public void onError(Throwable ex) {
long delayed = System.currentTimeMillis() - task.getLastModified();
LOGGER.error("[notify-exception] target:{} dataId:{} group:{} ts:{} ex:{}", task.target, task.getDataId(),
@ -219,7 +207,7 @@ public class AsyncNotifyService {
}
@Override
public void cancelled() {
public void onCancel() {
LogUtil.NOTIFY_LOG.error("[notify-exception] target:{} dataId:{} group:{} ts:{} method:{}", task.target,
task.getDataId(), task.getGroup(), task.getLastModified(), "CANCELED");
@ -231,10 +219,6 @@ public class AsyncNotifyService {
MetricsMonitor.getConfigNotifyException().increment();
}
private NotifySingleTask task;
private CloseableHttpAsyncClient httpClient;
}
static class NotifySingleTask extends NotifyTask {

View File

@ -0,0 +1,109 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.nacos.config.server.service.notify;
import com.alibaba.nacos.common.http.AbstractHttpClientFactory;
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
import com.alibaba.nacos.common.http.HttpClientConfig;
import com.alibaba.nacos.common.http.client.NacosAsyncRestTemplate;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.config.server.utils.PropertyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* http client manager.
*
* @author mai.jh
*/
public final class HttpClientManager {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientManager.class);
/**
* Connection timeout and socket timeout with other servers.
*/
private static final int TIMEOUT = 500;
private static final NacosRestTemplate NACOS_REST_TEMPLATE;
private static final NacosAsyncRestTemplate NACOS_ASYNC_REST_TEMPLATE;
static {
// build nacos rest template
NACOS_REST_TEMPLATE = HttpClientBeanHolder.getNacosRestTemplate(new ConfigHttpClientFactory(TIMEOUT, TIMEOUT));
NACOS_ASYNC_REST_TEMPLATE = HttpClientBeanHolder.getNacosAsyncRestTemplate(
new ConfigHttpClientFactory(PropertyUtil.getNotifyConnectTimeout(),
PropertyUtil.getNotifySocketTimeout()));
ThreadUtils.addShutdownHook(new Runnable() {
@Override
public void run() {
shutdown();
}
});
}
public static NacosRestTemplate getNacosRestTemplate() {
return NACOS_REST_TEMPLATE;
}
public static NacosAsyncRestTemplate getNacosAsyncRestTemplate() {
return NACOS_ASYNC_REST_TEMPLATE;
}
private static void shutdown() {
LOGGER.warn("[ConfigServer-HttpClientManager] Start destroying NacosRestTemplate");
try {
final String httpClientFactoryBeanName = ConfigHttpClientFactory.class.getName();
HttpClientBeanHolder.shutdownNacostSyncRest(httpClientFactoryBeanName);
HttpClientBeanHolder.shutdownNacosAsyncRest(httpClientFactoryBeanName);
} catch (Exception ex) {
LOGGER.error("[ConfigServer-HttpClientManager] An exception occurred when the HTTP client was closed : {}",
ExceptionUtil.getStackTrace(ex));
}
LOGGER.warn("[ConfigServer-HttpClientManager] Destruction of the end");
}
/**
* http client factory.
*/
private static class ConfigHttpClientFactory extends AbstractHttpClientFactory {
private final int conTimeOutMillis;
private final int readTimeOutMillis;
public ConfigHttpClientFactory(int conTimeOutMillis, int readTimeOutMillis) {
this.conTimeOutMillis = conTimeOutMillis;
this.readTimeOutMillis = readTimeOutMillis;
}
@Override
protected HttpClientConfig buildHttpClientConfig() {
return HttpClientConfig.builder().setConTimeOutMillis(conTimeOutMillis)
.setReadTimeOutMillis(readTimeOutMillis).build();
}
@Override
protected Logger assignLogger() {
return LOGGER;
}
}
}

View File

@ -16,17 +16,15 @@
package com.alibaba.nacos.config.server.service.notify;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.config.server.manager.TaskManager;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
/**
@ -53,65 +51,24 @@ public class NotifyService {
public static final String NOTIFY_HEADER_OP_HANDLE_IP = "opHandleIp";
private TaskManager notifyTaskManager;
/**
* Invoke http get request.
*
* @param url url
* @param headers headers
* @param encoding encoding
* @return {@link HttpResult}
* @throws IOException throw IOException
* @return {@link com.alibaba.nacos.common.model.RestResult}
* @throws Exception throw Exception
*/
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
public static HttpResult invokeURL(String url, List<String> headers, String encoding) throws IOException {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(TIMEOUT);
conn.setReadTimeout(TIMEOUT);
conn.setRequestMethod("GET");
if (null != headers && !StringUtils.isEmpty(encoding)) {
for (Iterator<String> iter = headers.iterator(); iter.hasNext(); ) {
conn.addRequestProperty(iter.next(), iter.next());
}
}
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + encoding);
// establish TCP connection
conn.connect();
// Send request internally
int respCode = conn.getResponseCode();
String resp = null;
if (HttpServletResponse.SC_OK == respCode) {
resp = IoUtils.toString(conn.getInputStream(), encoding);
} else {
resp = IoUtils.toString(conn.getErrorStream(), encoding);
}
return new HttpResult(respCode, resp);
} finally {
IoUtils.closeQuietly(conn);
public static RestResult<String> invokeURL(String url, List<String> headers, String encoding) throws Exception {
Header header = Header.newInstance();
header.addParam(HttpHeaderConsts.ACCEPT_CHARSET, encoding);
if (CollectionUtils.isNotEmpty(headers)) {
header.addAll(headers);
}
return HttpClientManager.getNacosRestTemplate().get(url, header, Query.EMPTY, String.class);
}
public static class HttpResult {
public final int code;
public String content;
public HttpResult(int code, String content) {
this.code = code;
this.content = content;
}
}
/**
* Connection timeout and socket timeout with other servers.
*/
static final int TIMEOUT = 500;
private TaskManager notifyTaskManager;
}

View File

@ -16,17 +16,16 @@
package com.alibaba.nacos.config.server.service.notify;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.manager.AbstractTask;
import com.alibaba.nacos.config.server.manager.TaskProcessor;
import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
import com.alibaba.nacos.config.server.service.notify.NotifyService.HttpResult;
import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.core.cluster.ServerMemberManager;
import com.alibaba.nacos.core.utils.ApplicationUtils;
import com.alibaba.nacos.core.utils.InetUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -78,8 +77,8 @@ public class NotifyTaskProcessor implements TaskProcessor {
String urlString = MessageFormat
.format(URL_PATTERN, serverIp, ApplicationUtils.getContextPath(), dataId, group);
HttpResult result = NotifyService.invokeURL(urlString, headers, Constants.ENCODE);
if (result.code == HttpStatus.SC_OK) {
RestResult<String> result = NotifyService.invokeURL(urlString, headers, Constants.ENCODE);
if (result.ok()) {
ConfigTraceService.logNotifyEvent(dataId, group, tenant, null, lastModified, InetUtils.getSelfIp(),
ConfigTraceService.NOTIFY_EVENT_OK, delayed, serverIp);
@ -89,7 +88,7 @@ public class NotifyTaskProcessor implements TaskProcessor {
} else {
MetricsMonitor.getConfigNotifyException().increment();
LOGGER.error("[notify-error] {}, {}, to {}, result {}",
new Object[] {dataId, group, serverIp, result.code});
new Object[] {dataId, group, serverIp, result.getCode()});
ConfigTraceService.logNotifyEvent(dataId, group, tenant, null, lastModified, InetUtils.getSelfIp(),
ConfigTraceService.NOTIFY_EVENT_ERROR, delayed, serverIp);
return false;

View File

@ -475,6 +475,7 @@ public final class RowMapperManager {
configHistoryInfo.setTenant(rs.getString("tenant_id"));
configHistoryInfo.setAppName(rs.getString("app_name"));
configHistoryInfo.setSrcIp(rs.getString("src_ip"));
configHistoryInfo.setSrcUser(rs.getString("src_user"));
configHistoryInfo.setOpType(rs.getString("op_type"));
configHistoryInfo.setCreatedTime(rs.getTimestamp("gmt_create"));
configHistoryInfo.setLastModifiedTime(rs.getTimestamp("gmt_modified"));

View File

@ -2005,7 +2005,7 @@ public class EmbeddedStoragePersistServiceImpl implements PersistService {
int pageSize) {
String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
String sqlCountRows = "select count(*) from his_config_info where data_id = ? and group_id = ? and tenant_id = ?";
String sqlFetchRows = "select nid,data_id,group_id,tenant_id,app_name,src_ip,op_type,gmt_create,gmt_modified from his_config_info where data_id = ? and group_id = ? and tenant_id = ? order by nid desc";
String sqlFetchRows = "select nid,data_id,group_id,tenant_id,app_name,src_ip,src_user,op_type,gmt_create,gmt_modified from his_config_info where data_id = ? and group_id = ? and tenant_id = ? order by nid desc";
PaginationHelper<ConfigHistoryInfo> helper = createPaginationHelper();
return helper.fetchPage(sqlCountRows, sqlFetchRows, new Object[] {dataId, group, tenantTmp}, pageNo, pageSize,

View File

@ -2240,7 +2240,7 @@ public class ExternalStoragePersistServiceImpl implements PersistService {
String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
String sqlCountRows = "select count(*) from his_config_info where data_id = ? and group_id = ? and tenant_id = ?";
String sqlFetchRows =
"select nid,data_id,group_id,tenant_id,app_name,src_ip,op_type,gmt_create,gmt_modified from his_config_info "
"select nid,data_id,group_id,tenant_id,app_name,src_ip,src_user,op_type,gmt_create,gmt_modified from his_config_info "
+ "where data_id = ? and group_id = ? and tenant_id = ? order by nid desc";
Page<ConfigHistoryInfo> page = null;
@ -2249,7 +2249,8 @@ public class ExternalStoragePersistServiceImpl implements PersistService {
.fetchPage(sqlCountRows, sqlFetchRows, new Object[] {dataId, group, tenantTmp}, pageNo, pageSize,
HISTORY_LIST_ROW_MAPPER);
} catch (DataAccessException e) {
LogUtil.FATAL_LOG.error("[list-config-history] error, dataId:{}, group:{}", new Object[] {dataId, group}, e);
LogUtil.FATAL_LOG
.error("[list-config-history] error, dataId:{}, group:{}", new Object[] {dataId, group}, e);
throw e;
}
return page;

View File

@ -1,57 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.alibaba.nacos.config.server.utils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
/**
* Json util.
*
* @author Nacos
*/
@SuppressWarnings({"PMD.ClassNamingShouldBeCamelRule", "checkstyle:AbbreviationAsWordInName"})
public class JSONUtils {
static ObjectMapper mapper = new ObjectMapper();
static {
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
public static String serializeObject(Object o) throws IOException {
return mapper.writeValueAsString(o);
}
public static Object deserializeObject(String s, Class<?> clazz) throws IOException {
return mapper.readValue(s, clazz);
}
public static <T> T deserializeObject(String s, TypeReference<T> typeReference) throws IOException {
return mapper.readValue(s, typeReference);
}
public static <T> T deserializeObject(InputStream src, TypeReference<T> typeReference) throws IOException {
return mapper.readValue(src, typeReference);
}
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.config.server.utils;
import com.alibaba.nacos.auth.model.User;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
@ -35,6 +36,8 @@ public class RequestUtil {
public static final String CLIENT_APPNAME_HEADER = "Client-AppName";
public static final String NACOS_USER_KEY = "nacosuser";
/**
* get real client ip
*
@ -63,4 +66,31 @@ public class RequestUtil {
return request.getHeader(CLIENT_APPNAME_HEADER);
}
/**
* Gets the user of the client application in the Attribute.
*
* @param request {@link HttpServletRequest}
* @return may be return null
*/
public static User getUser(HttpServletRequest request) {
Object userObj = request.getAttribute(NACOS_USER_KEY);
if (userObj == null) {
return null;
}
User user = (User) userObj;
return user;
}
/**
* Gets the username of the client application in the Attribute.
*
* @param request {@link HttpServletRequest}
* @return may be return null
*/
public static String getSrcUserName(HttpServletRequest request) {
User user = getUser(request);
return user == null ? null : user.getUserName();
}
}

View File

@ -85,7 +85,7 @@
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<relativePath>../pom.xml</relativePath>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
</parent>
<properties>

View File

@ -21,7 +21,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1</version>
<version>1.4.0-SNAPSHOT</version>
</parent>
<artifactId>nacos-console</artifactId>
<packaging>jar</packaging>
@ -76,20 +76,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>

View File

@ -16,14 +16,14 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.console.model.Namespace;
import com.alibaba.nacos.console.model.NamespaceAllInfo;
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.core.auth.ActionTypes;
import com.alibaba.nacos.core.auth.Secured;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;

View File

@ -16,11 +16,11 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.core.auth.ActionTypes;
import com.alibaba.nacos.core.auth.Secured;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;

View File

@ -16,11 +16,11 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.core.auth.ActionTypes;
import com.alibaba.nacos.core.auth.Secured;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
@ -30,6 +30,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Role operation controller.
*
@ -58,6 +60,18 @@ public class RoleController {
return roleService.getRolesFromDatabase(username, pageNo, pageSize);
}
/**
* Fuzzy matching role name .
*
* @param role role id
* @return role list
*/
@GetMapping("/search")
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.READ)
public List<String> searchRoles(@RequestParam String role) {
return roleService.findRolesLikeRoleName(role);
}
/**
* Add a role to a user
*

View File

@ -17,6 +17,11 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.common.AuthSystemTypes;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.config.server.auth.RoleInfo;
@ -28,11 +33,6 @@ import com.alibaba.nacos.console.security.nacos.users.NacosUser;
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.console.utils.JwtTokenUtils;
import com.alibaba.nacos.console.utils.PasswordEncoderUtil;
import com.alibaba.nacos.core.auth.AccessException;
import com.alibaba.nacos.core.auth.ActionTypes;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.auth.AuthSystemTypes;
import com.alibaba.nacos.core.auth.Secured;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
@ -248,4 +248,17 @@ public class UserController {
}
return rr;
}
/**
* Fuzzy matching username.
*
* @param username username
* @return Matched username
*/
@GetMapping("/search")
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
public List<String> searchUsersLikeUsername(@RequestParam String username) {
return userDetailsService.findUserLikeUsername(username);
}
}

View File

@ -16,8 +16,8 @@
package com.alibaba.nacos.console.exception;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.core.auth.AccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

View File

@ -16,10 +16,11 @@
package com.alibaba.nacos.console.security.nacos;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.auth.common.AuthConfigs;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@ -69,9 +70,8 @@ public class JwtTokenManager {
validity = new Date(now + authConfigs.getTokenValidityInSeconds() * 1000L);
Claims claims = Jwts.claims().setSubject(userName);
return Jwts.builder().setClaims(claims).setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, authConfigs.getSecretKey()).compact();
.signWith(Keys.hmacShaKeyFor(authConfigs.getSecretKeyBytes()), SignatureAlgorithm.HS256).compact();
}
/**
@ -81,8 +81,8 @@ public class JwtTokenManager {
* @return auth info
*/
public Authentication getAuthentication(String token) {
Claims claims = Jwts.parser().setSigningKey(authConfigs.getSecretKey()).parseClaimsJws(token).getBody();
Claims claims = Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build()
.parseClaimsJws(token).getBody();
List<GrantedAuthority> authorities = AuthorityUtils
.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
@ -97,6 +97,7 @@ public class JwtTokenManager {
* @param token token
*/
public void validateToken(String token) {
Jwts.parser().setSigningKey(authConfigs.getSecretKey()).parseClaimsJws(token);
Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build().parseClaimsJws(token);
}
}

View File

@ -16,10 +16,10 @@
package com.alibaba.nacos.console.security.nacos;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.common.AuthSystemTypes;
import com.alibaba.nacos.console.filter.JwtAuthenticationTokenFilter;
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.auth.AuthSystemTypes;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

View File

@ -17,13 +17,14 @@
package com.alibaba.nacos.console.security.nacos;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.auth.AuthManager;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.Permission;
import com.alibaba.nacos.auth.model.User;
import com.alibaba.nacos.config.server.auth.RoleInfo;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
import com.alibaba.nacos.core.auth.AccessException;
import com.alibaba.nacos.core.auth.AuthManager;
import com.alibaba.nacos.core.auth.Permission;
import com.alibaba.nacos.core.auth.User;
import com.alibaba.nacos.core.utils.Loggers;
import io.jsonwebtoken.ExpiredJwtException;
import org.apache.commons.lang3.StringUtils;
@ -90,7 +91,7 @@ public class NacosAuthManager implements AuthManager {
}
}
}
req.setAttribute(RequestUtil.NACOS_USER_KEY, user);
return user;
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.console.security.nacos.roles;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.model.Permission;
import com.alibaba.nacos.config.server.auth.PermissionInfo;
import com.alibaba.nacos.config.server.auth.PermissionPersistService;
import com.alibaba.nacos.config.server.auth.RoleInfo;
@ -23,8 +25,6 @@ import com.alibaba.nacos.config.server.auth.RolePersistService;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.auth.Permission;
import com.alibaba.nacos.core.utils.Loggers;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.lang3.StringUtils;
@ -235,4 +235,8 @@ public class NacosRoleServiceImpl {
public void deletePermission(String role, String resource, String action) {
permissionPersistService.deletePermission(role, resource, action);
}
public List<String> findRolesLikeRoleName(String role) {
return rolePersistService.findRolesLikeRoleName(role);
}
}

View File

@ -16,7 +16,7 @@
package com.alibaba.nacos.console.security.nacos.users;
import com.alibaba.nacos.core.auth.User;
import com.alibaba.nacos.auth.model.User;
/**
* Nacos User.

View File

@ -16,10 +16,10 @@
package com.alibaba.nacos.console.security.nacos.users;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.config.server.auth.UserPersistService;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.User;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
@ -28,6 +28,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -99,7 +100,11 @@ public class NacosUserDetailsServiceImpl implements UserDetailsService {
public User getUserFromDatabase(String username) {
return userPersistService.findUserByUsername(username);
}
public List<String> findUserLikeUsername(String username) {
return userPersistService.findUserLikeUsername(username);
}
public void createUser(String username, String password) {
userPersistService.createUser(username, password);
}

View File

@ -21,9 +21,9 @@ import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecurityException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@ -127,9 +127,7 @@ public class JwtTokenUtils {
* @return auth info
*/
public Authentication getAuthentication(String token) {
Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
Claims claims = Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody();
List<GrantedAuthority> authorities = AuthorityUtils
.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
@ -145,9 +143,9 @@ public class JwtTokenUtils {
*/
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token);
return true;
} catch (SignatureException e) {
} catch (SecurityException e) {
log.info("Invalid JWT signature.");
log.trace("Invalid JWT signature trace: {}", e);
} catch (MalformedJwtException e) {

View File

@ -29,7 +29,7 @@ server.port=8848
#*************** Config Module Related Configurations ***************#
### If user MySQL as datasource:
### If use MySQL as datasource:
# spring.datasource.platform=mysql
### Count of DB:
@ -37,8 +37,8 @@ server.port=8848
### Connect URL of DB:
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# db.user=root
# db.password=1017
# db.user=nacos
# db.password=nacos
#*************** Naming Module Related Configurations ***************#
@ -154,6 +154,12 @@ nacos.istio.mcp.server.enabled=false
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist
#*************** JRaft Related Configurations ***************#

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -23,7 +23,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Nacos</title>
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="img/nacos-logo.png" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="css/console1412.css">
<!-- 第三方css开始 -->

View File

@ -38,3 +38,5 @@ export const PERMISSIONS_LIST = 'PERMISSIONS_LIST';
export const GET_NAMESPACES = 'GET_NAMESPACES';
export const GET_CONFIGURATION = 'GET_CONFIGURATION';
export const GLOBAL_PAGE_SIZE_LIST = [10, 20, 30, 50, 100];

View File

@ -74,7 +74,9 @@ class Header extends React.Component {
}
return '';
};
indexAction = () => {
this.props.history.push('/');
};
render() {
const {
locale = {},
@ -94,11 +96,7 @@ class Header extends React.Component {
<>
<header className="header-container header-container-primary">
<div className="header-body">
<a
href={`https://nacos.io/${language.toLocaleLowerCase()}/`}
target="_blank"
rel="noopener noreferrer"
>
<a href="#" onClick={this.indexAction} rel="noopener noreferrer">
<img
src="img/logo-2000-390.svg"
className="logo"

View File

@ -58,7 +58,6 @@ request.middleWare((_config = {}) => {
if (res.code === 403 && !hasAlert) {
hasAlert = true;
window.Dialog.alert({
language: aliwareIntl.currentLanguageCode || 'zh-cn',
style: { width: 400 },
content: res.message,
onOk: () => {
@ -81,7 +80,6 @@ request.middleWare((_config = {}) => {
hasAlert = true;
window.Dialog.alert({
language: aliwareIntl.currentLanguageCode || 'zh-cn',
style: { width: 400 },
content: aliwareIntl.get('com.alibaba.nacos.pubshow'), // '子账号没有权限请联系主账号负责人RAM上授权',
onOk: () => {

View File

@ -94,6 +94,7 @@ const I18N_CONF = {
namespaceNames: 'Namespaces',
namespaceNumber: 'Namespace ID',
namespaceOperation: 'Actions',
refresh: 'Refresh',
},
ServiceList: {
serviceList: 'Service List',
@ -222,6 +223,7 @@ const I18N_CONF = {
queryResult: 'Search Results: Found',
articleMeet: 'configuration items.',
lastUpdateTime: 'Last Modified At',
operator: 'Operator',
operation: 'Operation',
},
HistoryDetail: {
@ -233,6 +235,7 @@ const I18N_CONF = {
moreAdvancedOptions: 'Advanced Options',
home: 'Application:',
actionType: 'Action Type:',
operator: 'Operator:',
configureContent: 'Configuration Content:',
back: 'Back',
},
@ -306,6 +309,7 @@ const I18N_CONF = {
cloneSuccEnd: 'configuration items cloned',
cloneFail: 'Clone failed',
getNamespaceFailed: 'get the namespace failed',
getNamespace403: 'Without permission to access ${namespaceName} namespace!',
startCloning: 'Start Clone',
cloningConfiguration: 'Clone config',
source: 'Source :',
@ -319,6 +323,7 @@ const I18N_CONF = {
delSelectedAlertContent: 'please select the configuration to delete',
delSuccessMsg: 'delete successful',
cloneEditableTitle: 'Modify Data Id and Group (optional)',
authFail: 'Auth failed',
},
NewConfig: {
newListingMain: 'Create Configuration',
@ -519,6 +524,7 @@ const I18N_CONF = {
username: 'Username',
password: 'Password',
operation: 'Operation',
refresh: 'Refresh',
},
NewUser: {
createUser: 'Create user',
@ -552,6 +558,7 @@ const I18N_CONF = {
operation: 'Operation',
deleteRole: 'Delete',
deleteRoleTip: 'Do you want to delete this role?',
refresh: 'Refresh',
},
NewRole: {
bindingRoles: 'Binding roles',
@ -574,6 +581,7 @@ const I18N_CONF = {
readOnly: 'read only',
writeOnly: 'write only',
readWrite: 'Read and write',
refresh: 'Refresh',
},
NewPermissions: {
addPermission: 'Add Permission',

View File

@ -94,6 +94,7 @@ const I18N_CONF = {
namespaceNames: '命名空间名称',
namespaceNumber: '命名空间ID',
namespaceOperation: '操作',
refresh: '刷新',
},
ServiceList: {
serviceList: '服务列表',
@ -222,6 +223,7 @@ const I18N_CONF = {
queryResult: '查询结果共查询到',
articleMeet: '条满足要求的配置',
lastUpdateTime: '最后更新时间',
operator: '操作人',
operation: '操作',
},
HistoryDetail: {
@ -234,6 +236,7 @@ const I18N_CONF = {
home: '归属应用:',
actionType: '操作类型:',
configureContent: '配置内容:',
operator: '操作人:',
back: '返回',
},
DashboardCard: {
@ -304,6 +307,7 @@ const I18N_CONF = {
cloneSuccEnd: '项配置',
cloneFail: '克隆失败',
getNamespaceFailed: '获取命名空间失败',
getNamespace403: '没有 ${namespaceName} 命名空间的访问权限',
startCloning: '开始克隆',
cloningConfiguration: '克隆配置',
source: '源空间',
@ -317,6 +321,7 @@ const I18N_CONF = {
delSelectedAlertContent: '请选择要删除的配置',
delSuccessMsg: '删除成功',
cloneEditableTitle: '修改 Data Id Group (可选操作)',
authFail: '权限认证失败',
},
NewConfig: {
newListingMain: '新建配置',
@ -516,6 +521,7 @@ const I18N_CONF = {
username: '用户名',
password: '密码',
operation: '操作',
refresh: '刷新',
},
NewUser: {
createUser: '创建用户',
@ -549,6 +555,7 @@ const I18N_CONF = {
operation: '操作',
deleteRole: '删除',
deleteRoleTip: '是否要删除该角色',
refresh: '刷新',
},
NewRole: {
bindingRoles: '绑定角色',
@ -571,6 +578,7 @@ const I18N_CONF = {
readOnly: '只读',
writeOnly: '只写',
readWrite: '读写',
refresh: '刷新',
},
NewPermissions: {
addPermission: '添加权限',

View File

@ -19,6 +19,7 @@ import PropTypes from 'prop-types';
import { Field, Form, Input, Select, Dialog, ConfigProvider } from '@alifd/next';
import { connect } from 'react-redux';
import { getNamespaces } from '../../../reducers/namespace';
import { searchRoles } from '../../../reducers/authority';
const FormItem = Form.Item;
const { Option } = Select;
@ -28,7 +29,7 @@ const formItemLayout = {
wrapperCol: { span: 19 },
};
@connect(state => ({ namespaces: state.namespace.namespaces }), { getNamespaces })
@connect(state => ({ namespaces: state.namespace.namespaces }), { getNamespaces, searchRoles })
@ConfigProvider.config
class NewPermissions extends React.Component {
static displayName = 'NewPermissions';
@ -39,11 +40,15 @@ class NewPermissions extends React.Component {
locale: PropTypes.object,
visible: PropTypes.bool,
getNamespaces: PropTypes.func,
getRoles: PropTypes.func,
onOk: PropTypes.func,
onCancel: PropTypes.func,
namespaces: PropTypes.array,
};
state = {
dataSource: [],
};
componentDidMount() {
this.props.getNamespaces();
}
@ -68,6 +73,14 @@ class NewPermissions extends React.Component {
return null;
}
handleChange = value => {
if (value.length > 0) {
searchRoles(value).then(val => {
this.setState({ dataSource: val });
});
}
};
render() {
const { getError } = this.field;
const { visible, onOk, onCancel, locale, namespaces } = this.props;
@ -88,7 +101,14 @@ class NewPermissions extends React.Component {
>
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
<FormItem label={locale.role} required help={getError('role')}>
<Input name="role" trim placeholder={locale.rolePlaceholder} />
<Select.AutoComplete
name="role"
style={{ width: 316 }}
filterLocal={false}
placeholder={locale.rolePlaceholder}
onChange={this.handleChange}
dataSource={this.state.dataSource}
/>
</FormItem>
<FormItem label={locale.resource} required help={getError('resource')}>
<Select

View File

@ -60,6 +60,7 @@ class PermissionsManagement extends React.Component {
}
getPermissions() {
this.setState({ loading: true });
const { pageNo, pageSize } = this.state;
this.props
.getPermissions({ pageNo, pageSize })
@ -94,6 +95,9 @@ class PermissionsManagement extends React.Component {
<Button type="primary" onClick={() => this.setState({ createPermissionVisible: true })}>
{locale.addPermission}
</Button>
<Button type="secondary" onClick={() => this.getPermissions()}>
{locale.refresh}
</Button>
</div>
<Table dataSource={permissions.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
<Table.Column title={locale.role} dataIndex="role" />

View File

@ -16,7 +16,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Field, Form, Input, Dialog, ConfigProvider } from '@alifd/next';
import { connect } from 'react-redux';
import { Field, Form, Input, Dialog, ConfigProvider, Select } from '@alifd/next';
import { searchUsers } from '../../../reducers/authority';
const FormItem = Form.Item;
@ -24,7 +26,7 @@ const formItemLayout = {
labelCol: { fixedSpan: 4 },
wrapperCol: { span: 19 },
};
@connect(state => ({ users: state.authority.users }), { searchUsers })
@ConfigProvider.config
class NewRole extends React.Component {
static displayName = 'NewRole';
@ -35,9 +37,14 @@ class NewRole extends React.Component {
locale: PropTypes.object,
visible: PropTypes.bool,
onOk: PropTypes.func,
getUsers: PropTypes.func,
onCancel: PropTypes.func,
};
state = {
dataSource: [],
};
check() {
const { locale } = this.props;
const errors = {
@ -57,6 +64,14 @@ class NewRole extends React.Component {
return null;
}
handleChange = value => {
if (value.length > 0) {
searchUsers(value).then(val => {
this.setState({ dataSource: val });
});
}
};
render() {
const { locale } = this.props;
const { getError } = this.field;
@ -81,7 +96,14 @@ class NewRole extends React.Component {
<Input name="role" trim placeholder={locale.rolePlaceholder} />
</FormItem>
<FormItem label={locale.username} required help={getError('username')}>
<Input name="username" placeholder={locale.usernamePlaceholder} />
<Select.AutoComplete
name="username"
style={{ width: 316 }}
filterLocal={false}
placeholder={locale.usernamePlaceholder}
onChange={this.handleChange}
dataSource={this.state.dataSource}
/>
</FormItem>
</Form>
</Dialog>

View File

@ -49,6 +49,7 @@ class RolesManagement extends React.Component {
}
getRoles() {
this.setState({ loading: true });
const { pageNo, pageSize } = this.state;
this.props
.getRoles({ pageNo, pageSize })
@ -74,6 +75,9 @@ class RolesManagement extends React.Component {
<Button type="primary" onClick={() => this.setState({ createRoleVisible: true })}>
{locale.bindingRoles}
</Button>
<Button type="secondary" onClick={() => this.getRoles()}>
{locale.refresh}
</Button>
</div>
<Table dataSource={roles.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
<Table.Column title={locale.role} dataIndex="role" />

View File

@ -51,6 +51,7 @@ class UserManagement extends React.Component {
}
getUsers() {
this.setState({ loading: true });
const { pageNo, pageSize } = this.state;
this.props
.getUsers({ pageNo, pageSize })
@ -76,6 +77,9 @@ class UserManagement extends React.Component {
<Button type="primary" onClick={() => this.setState({ createUserVisible: true })}>
{locale.createUser}
</Button>
<Button type="secondary" onClick={() => this.getUsers()}>
{locale.refresh}
</Button>
</div>
<Table dataSource={users.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
<Table.Column title={locale.username} dataIndex="username" />

View File

@ -134,6 +134,8 @@ class ConfigDetail extends React.Component {
self.field.setValue('config_tags', data.configTags);
self.field.setValue('desc', data.desc);
self.field.setValue('md5', data.md5);
self.field.setValue('type', data.type);
self.initMoacoEditor(data.type, data.content);
} else {
Dialog.alert({ title: locale.error, content: result.message });
}
@ -157,6 +159,35 @@ class ConfigDetail extends React.Component {
);
}
initMoacoEditor(language, value) {
const container = document.getElementById('container');
container.innerHTML = '';
this.monacoEditor = null;
const options = {
value,
language,
codeLens: true,
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: true,
lineNumbersMinChars: true,
theme: 'vs-dark',
wordWrapColumn: 120,
folding: false,
showFoldingControls: 'always',
wordWrap: 'wordWrapColumn',
cursorStyle: 'line',
automaticLayout: true,
};
if (!window.monaco) {
window.importEditor(() => {
this.monacoEditor = window.monaco.editor.create(container, options);
});
} else {
this.monacoEditor = window.monaco.editor.create(container, options);
}
}
render() {
const { locale = {} } = this.props;
const { init } = this.field;
@ -243,7 +274,7 @@ class ConfigDetail extends React.Component {
<Input htmlType={'text'} readOnly {...init('md5')} />
</FormItem>
<FormItem label={locale.configuration} required {...formItemLayout}>
<Input.TextArea htmlType={'text'} multiple rows={15} readOnly {...init('content')} />
<div style={{ clear: 'both', height: 300 }} id="container" />
</FormItem>
<FormItem label={' '} {...formItemLayout}>
<Button type={'primary'} onClick={this.goList.bind(this)}>

View File

@ -46,7 +46,7 @@ import { connect } from 'react-redux';
import { getConfigs } from '../../../reducers/configuration';
import './index.scss';
import { LANGUAGE_KEY } from '../../../constants';
import { LANGUAGE_KEY, GLOBAL_PAGE_SIZE_LIST } from '../../../constants';
const { Panel } = Collapse;
const configsTableSelected = new Map();
@ -250,6 +250,7 @@ class ConfigurationManagement extends React.Component {
if (this.state.loading) {
return;
}
const { locale = {}, configurations = {} } = this.props;
this.tenant = getParams('namespace') || ''; // 为当前实例保存tenant参数
this.serverId = getParams('serverId') || '';
const prePageNo = getParams('pageNo');
@ -273,14 +274,32 @@ class ConfigurationManagement extends React.Component {
params.search = 'accurate';
}
this.setState({ loading: true });
this.props.getConfigs(params).then(() =>
this.setState({
loading: false,
selectedRecord: [],
selectedKeys: [],
tenant: this.tenant,
})
);
this.props
.getConfigs(params)
.then(() =>
this.setState({
loading: false,
selectedRecord: [],
selectedKeys: [],
tenant: this.tenant,
})
)
.catch(res => {
configurations.pageItems = [];
configurations.totalCount = 0;
this.setState({
loading: false,
});
if (res && [401, 403].includes(res.status)) {
Dialog.alert({
title: locale.authFail,
content: locale.getNamespace403.replace(
'${namespaceName}',
this.state.nownamespace_name
),
});
}
});
}
showMore() {}
@ -1384,7 +1403,7 @@ class ConfigurationManagement extends React.Component {
</div>
<Pagination
style={{ float: 'right' }}
pageSizeList={[10, 20, 30]}
pageSizeList={GLOBAL_PAGE_SIZE_LIST}
pageSizePosition="start"
pageSizeSelector="dropdown"
popupProps={{ align: 'bl tl' }}

View File

@ -74,6 +74,7 @@ class HistoryDetail extends React.Component {
self.field.setValue('content', data.content);
self.field.setValue('appName', self.inApp ? self.edasAppName : data.appName);
self.field.setValue('envs', self.serverId);
self.field.setValue('srcUser', self.srcUser);
self.field.setValue('opType', typeMap[data.opType.trim()]);
self.field.setValue('group', data.group);
self.field.setValue('md5', data.md5);
@ -119,6 +120,9 @@ class HistoryDetail extends React.Component {
<Input htmlType="text" readOnly {...init('appName')} />
</Form.Item>
</div>
<Form.Item label={locale.operator} required {...formItemLayout}>
<Input htmlType="text" readOnly {...init('srcUser')} />
</Form.Item>
<Form.Item label={locale.actionType} required {...formItemLayout}>
<Input htmlType="text" readOnly {...init('opType')} />
</Form.Item>

View File

@ -293,6 +293,7 @@ class HistoryRollback extends React.Component {
<Table dataSource={this.state.dataSource} locale={{ empty: locale.pubNoData }}>
<Table.Column title="Data ID" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
<Table.Column title={locale.operator} dataIndex="srcUser" />
<Table.Column
title={locale.lastUpdateTime}
dataIndex="lastModifiedTime"

View File

@ -266,7 +266,6 @@ class NewConfig extends React.Component {
} else {
Dialog.confirm({
content: locale.confirmSyanx,
language: aliwareIntl.currentLanguageCode || 'zh-cn',
onOk: () => {
this.publicConfigBeforeCheck(content);
},
@ -352,7 +351,6 @@ class NewConfig extends React.Component {
error: res => {
this.closeLoading();
Dialog.alert({
language: aliwareIntl.currentLanguageCode || 'zh-cn',
content: locale.publishFailed,
});
},

View File

@ -47,53 +47,51 @@ class NameSpace extends React.Component {
this.getNameSpaces(0);
}
getNameSpaces(delayTime = 2000) {
getNameSpaces() {
const { locale = {} } = this.props;
const { prompt } = locale;
const self = this;
self.openLoading();
setTimeout(() => {
request({
type: 'get',
beforeSend() {},
url: 'v1/console/namespaces',
success: res => {
if (res.code === 200) {
const data = res.data || [];
window.namespaceList = data;
request({
type: 'get',
beforeSend() {},
url: 'v1/console/namespaces',
success: res => {
if (res.code === 200) {
const data = res.data || [];
window.namespaceList = data;
for (let i = 0; i < data.length; i++) {
if (data[i].type === 1) {
this.setState({
defaultNamespace: data[i].namespace,
});
}
for (let i = 0; i < data.length; i++) {
if (data[i].type === 1) {
this.setState({
defaultNamespace: data[i].namespace,
});
}
this.setState({
dataSource: data,
});
} else {
Dialog.alert({
title: prompt,
content: res.message,
});
}
},
complete() {
self.closeLoading();
},
error: res => {
window.namespaceList = [
{
namespace: '',
namespaceShowName: '公共空间',
type: 0,
},
];
},
});
}, delayTime);
this.setState({
dataSource: data,
});
} else {
Dialog.alert({
title: prompt,
content: res.message,
});
}
},
complete() {
self.closeLoading();
},
error: res => {
window.namespaceList = [
{
namespace: '',
namespaceShowName: '公共空间',
type: 0,
},
];
},
});
}
openLoading() {
@ -315,6 +313,13 @@ class NameSpace extends React.Component {
>
{namespaceAdd}
</Button>
<Button
style={{ marginRight: 0, marginTop: 10 }}
type="secondary"
onClick={() => this.getNameSpaces()}
>
{locale.refresh}
</Button>
</div>
<div>
<Table dataSource={this.state.dataSource} locale={{ empty: pubNoData }}>

View File

@ -37,6 +37,7 @@ import EditServiceDialog from '../ServiceDetail/EditServiceDialog';
import ShowServiceCodeing from 'components/ShowCodeing/ShowServiceCodeing';
import './ServiceList.scss';
import { GLOBAL_PAGE_SIZE_LIST } from '../../../constants';
const FormItem = Form.Item;
const { Row, Col } = Grid;
@ -94,12 +95,14 @@ class ServiceList extends React.Component {
`serviceNameParam=${search.serviceName}`,
`groupNameParam=${search.groupName}`,
];
this.openLoading();
request({
url: `v1/ns/catalog/services?${parameter.join('&')}`,
success: ({ count = 0, serviceList = [] } = {}) => {
this.setState({
dataSource: serviceList,
total: count,
loading: false,
});
},
error: () =>
@ -107,6 +110,7 @@ class ServiceList extends React.Component {
dataSource: [],
total: 0,
currentPage: 0,
loading: false,
}),
});
}
@ -129,6 +133,10 @@ class ServiceList extends React.Component {
this.showcode.current.getInstance().openDialog(record);
}
handlePageSizeChange(pageSize) {
this.setState({ pageSize }, () => this.queryServiceList());
}
deleteService(service) {
const { locale = {} } = this.props;
const { prompt, promptDelete } = locale;
@ -187,156 +195,143 @@ class ServiceList extends React.Component {
return (
<div className="main-container service-management">
<Loading
shape="flower"
<div style={{ marginTop: -15 }}>
<RegionGroup
setNowNameSpace={this.setNowNameSpace}
namespaceCallBack={this.getQueryLater}
/>
</div>
<h3 className="page-title">
<span className="title-item">{serviceList}</span>
<span className="title-item">|</span>
<span className="title-item">{nowNamespaceName}</span>
<span className="title-item">{nowNamespaceId}</span>
</h3>
<Row
className="demo-row"
style={{
position: 'relative',
width: '100%',
marginBottom: 10,
padding: 0,
}}
visible={this.state.loading}
tip="Loading..."
color="#333"
>
<div style={{ marginTop: -15 }}>
<RegionGroup
setNowNameSpace={this.setNowNameSpace}
namespaceCallBack={this.getQueryLater}
/>
</div>
<h3 className="page-title">
<span className="title-item">{serviceList}</span>
<span className="title-item">|</span>
<span className="title-item">{nowNamespaceName}</span>
<span className="title-item">{nowNamespaceId}</span>
</h3>
<Row
className="demo-row"
style={{
marginBottom: 10,
padding: 0,
}}
>
<Col span="24">
<Form inline field={this.field}>
<FormItem label={serviceName}>
<Input
placeholder={serviceNamePlaceholder}
style={{ width: 200 }}
value={search.serviceName}
onChange={serviceName => this.setState({ search: { ...search, serviceName } })}
onPressEnter={() =>
this.setState({ currentPage: 1 }, () => this.queryServiceList())
}
/>
</FormItem>
<FormItem label={groupName}>
<Input
placeholder={groupNamePlaceholder}
style={{ width: 200 }}
value={search.groupName}
onChange={groupName => this.setState({ search: { ...search, groupName } })}
onPressEnter={() =>
this.setState({ currentPage: 1 }, () => this.queryServiceList())
}
/>
</FormItem>
<Form.Item label={`${hiddenEmptyService}:`}>
<Switch
checked={hasIpCount}
onChange={hasIpCount =>
this.setState({ hasIpCount, currentPage: 1 }, () => {
localStorage.setItem('hasIpCount', hasIpCount);
this.queryServiceList();
})
}
/>
</Form.Item>
<FormItem label="">
<Button
type="primary"
onClick={() => this.setState({ currentPage: 1 }, () => this.queryServiceList())}
style={{ marginRight: 10 }}
>
{query}
</Button>
</FormItem>
<FormItem label="" style={{ float: 'right' }}>
<Button type="secondary" onClick={() => this.openEditServiceDialog()}>
{create}
</Button>
</FormItem>
</Form>
</Col>
</Row>
<Row style={{ padding: 0 }}>
<Col span="24" style={{ padding: 0 }}>
<Table
dataSource={this.state.dataSource}
locale={{ empty: pubNoData }}
getRowProps={row => this.rowColor(row)}
>
<Column title={locale.columnServiceName} dataIndex="name" />
<Column title={locale.groupName} dataIndex="groupName" />
<Column title={locale.columnClusterCount} dataIndex="clusterCount" />
<Column title={locale.columnIpCount} dataIndex="ipCount" />
<Column
title={locale.columnHealthyInstanceCount}
dataIndex="healthyInstanceCount"
<Col span="24">
<Form inline field={this.field}>
<FormItem label={serviceName}>
<Input
placeholder={serviceNamePlaceholder}
style={{ width: 200 }}
value={search.serviceName}
onChange={serviceName => this.setState({ search: { ...search, serviceName } })}
onPressEnter={() =>
this.setState({ currentPage: 1 }, () => this.queryServiceList())
}
/>
<Column title={locale.columnTriggerFlag} dataIndex="triggerFlag" />
<Column
title={operation}
align="center"
cell={(value, index, record) => (
// @author yongchao9 #2019年05月18日 下午5:46:28
/* Add a link to view "sample code"
</FormItem>
<FormItem label={groupName}>
<Input
placeholder={groupNamePlaceholder}
style={{ width: 200 }}
value={search.groupName}
onChange={groupName => this.setState({ search: { ...search, groupName } })}
onPressEnter={() =>
this.setState({ currentPage: 1 }, () => this.queryServiceList())
}
/>
</FormItem>
<Form.Item label={`${hiddenEmptyService}:`}>
<Switch
checked={hasIpCount}
onChange={hasIpCount =>
this.setState({ hasIpCount, currentPage: 1 }, () => {
localStorage.setItem('hasIpCount', hasIpCount);
this.queryServiceList();
})
}
/>
</Form.Item>
<FormItem label="">
<Button
type="primary"
onClick={() => this.setState({ currentPage: 1 }, () => this.queryServiceList())}
style={{ marginRight: 10 }}
>
{query}
</Button>
</FormItem>
<FormItem label="" style={{ float: 'right' }}>
<Button type="secondary" onClick={() => this.openEditServiceDialog()}>
{create}
</Button>
</FormItem>
</Form>
</Col>
</Row>
<Row style={{ padding: 0 }}>
<Col span="24" style={{ padding: 0 }}>
<Table
dataSource={this.state.dataSource}
locale={{ empty: pubNoData }}
getRowProps={row => this.rowColor(row)}
loading={this.state.loading}
>
<Column title={locale.columnServiceName} dataIndex="name" />
<Column title={locale.groupName} dataIndex="groupName" />
<Column title={locale.columnClusterCount} dataIndex="clusterCount" />
<Column title={locale.columnIpCount} dataIndex="ipCount" />
<Column title={locale.columnHealthyInstanceCount} dataIndex="healthyInstanceCount" />
<Column title={locale.columnTriggerFlag} dataIndex="triggerFlag" />
<Column
title={operation}
align="center"
cell={(value, index, record) => (
// @author yongchao9 #2019年05月18日 下午5:46:28
/* Add a link to view "sample code"
replace the original button with a label,
which is consistent with the operation style in configuration management.
*/
<div>
<a
onClick={() => {
const { name, groupName } = record;
this.props.history.push(
generateUrl('/serviceDetail', { name, groupName })
);
}}
style={{ marginRight: 5 }}
>
{detail}
</a>
<span style={{ marginRight: 5 }}>|</span>
<a style={{ marginRight: 5 }} onClick={() => this.showSampleCode(record)}>
{sampleCode}
</a>
<span style={{ marginRight: 5 }}>|</span>
<a onClick={() => this.deleteService(record)} style={{ marginRight: 5 }}>
{deleteAction}
</a>
</div>
)}
/>
</Table>
</Col>
</Row>
{this.state.total > this.state.pageSize && (
<div
style={{
marginTop: 10,
textAlign: 'right',
}}
>
<Pagination
current={this.state.currentPage}
total={this.state.total}
pageSize={this.state.pageSize}
onChange={currentPage =>
this.setState({ currentPage }, () => this.queryServiceList())
}
<div>
<a
onClick={() => {
const { name, groupName } = record;
this.props.history.push(generateUrl('/serviceDetail', { name, groupName }));
}}
style={{ marginRight: 5 }}
>
{detail}
</a>
<span style={{ marginRight: 5 }}>|</span>
<a style={{ marginRight: 5 }} onClick={() => this.showSampleCode(record)}>
{sampleCode}
</a>
<span style={{ marginRight: 5 }}>|</span>
<a onClick={() => this.deleteService(record)} style={{ marginRight: 5 }}>
{deleteAction}
</a>
</div>
)}
/>
</div>
)}
</Loading>
</Table>
</Col>
</Row>
<div
style={{
marginTop: 10,
textAlign: 'right',
}}
>
<Pagination
current={this.state.currentPage}
pageSizeList={GLOBAL_PAGE_SIZE_LIST}
pageSizePosition="start"
pageSizeSelector="dropdown"
popupProps={{ align: 'bl tl' }}
total={this.state.total}
pageSize={this.state.pageSize}
onPageSizeChange={pageSize => this.handlePageSizeChange(pageSize)}
onChange={currentPage => this.setState({ currentPage }, () => this.queryServiceList())}
/>
</div>
<ShowServiceCodeing ref={this.showcode} />
<EditServiceDialog
ref={this.editServiceDialog}

View File

@ -60,6 +60,13 @@ const getUsers = params => dispatch =>
const createUser = ([username, password]) =>
request.post('v1/auth/users', { username, password }).then(res => successMsg(res));
/**
* 通过username 模糊匹配
* @param {*} param0
*/
const searchUsers = username =>
request.get('v1/auth/users/search', { params: { username } }).then(res => successMsg(res));
/**
* 删除用户
* @param {*} username
@ -82,6 +89,13 @@ const passwordReset = ([username, newPassword]) =>
const getRoles = params => dispatch =>
request.get('v1/auth/roles', { params }).then(data => dispatch({ type: ROLE_LIST, data }));
/**
* 通过username 模糊匹配
* @param {*} param0
*/
const searchRoles = role =>
request.get('v1/auth/roles/search', { params: { role } }).then(res => successMsg(res));
/**
* 创建角色
* @param {*} param0
@ -133,10 +147,12 @@ export default (state = initialState, action) => {
};
export {
searchUsers,
getUsers,
createUser,
deleteUser,
passwordReset,
searchRoles,
getRoles,
createRole,
deleteRole,

View File

@ -16,6 +16,92 @@
import * as yamljs from 'yamljs';
/**
* 校验一个配置项
*/
function validateProperty(property) {
let { length } = property;
let keyLen = 0;
let valueStart = length;
let hasSep = false;
let precedingBackslash = false;
let c;
// 解析 key
while (keyLen < length) {
c = property[keyLen];
if ((c === '=' || c === ':') && !precedingBackslash) {
valueStart = keyLen + 1;
hasSep = true;
break;
}
if ((c === ' ' || c === '\t' || c === '\f') && !precedingBackslash) {
valueStart = keyLen + 1;
break;
}
if (c === '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
keyLen++;
}
// 解析 value
while (valueStart < length) {
c = property[valueStart];
if (c !== ' ' && c !== '\t' && c !== '\f') {
if (!hasSep && (c === '=' || c === ':')) {
hasSep = true;
} else {
break;
}
}
valueStart++;
}
return (
validateKeyOrValueForProperty(property, 0, keyLen) &&
validateKeyOrValueForProperty(property, valueStart, length)
);
}
function validateKeyOrValueForProperty(property, start, end) {
// check null
if (start >= end) {
return false;
}
let index = 0;
let c;
while (index < property.length) {
c = property[index++];
if (c !== '\\') {
continue;
}
c = property[index++];
// check backslash
if (!isPropertyEscape(c)) {
return false;
}
// check Unicode
if (c === 'u') {
let unicode = property.slice(index, index + 4).join('');
if (unicode.match(/^[a-f0-9]{4}$/i) === null) {
return false;
}
index += 4;
}
}
return true;
}
function isPropertyEscape(c = '') {
return 'abfnrt\\"\'0! #:=u'.includes(c);
}
export default {
/**
* 检测json是否合法
@ -65,12 +151,91 @@ export default {
* 检测属性是否正确
*/
validateProperties(str = '') {
const reg = /^[^=]+=.+$/;
return str
.replace('\n\r', '\n')
.split('\n')
.filter(_str => _str)
.every(_str => reg.test(_str.trim()));
let isNewLine = true;
let isCommentLine = false;
let isSkipWhiteSpace = true;
let precedingBackslash = false;
let appendedLineBegin = false;
let skipLF = false;
let hasProperty = false;
let property = [];
for (let i = 0; i < str.length; i++) {
let c = str[i];
if (skipLF) {
skipLF = false;
if (c === '\n') {
continue;
}
}
// 跳过行首空白字符
if (isSkipWhiteSpace) {
if (c === ' ' || c === '\t' || c === '\f') {
continue;
}
if (!appendedLineBegin && (c === '\r' || c === '\n')) {
continue;
}
appendedLineBegin = false;
isSkipWhiteSpace = false;
}
// 判断注释行
if (isNewLine) {
isNewLine = false;
if (c === '#' || c === '!') {
isCommentLine = true;
continue;
}
}
if (c !== '\n' && c !== '\r') {
property.push(c);
if (c === '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
continue;
}
// 跳过注释行
if (isCommentLine || property.length === 0) {
isNewLine = true;
isCommentLine = false;
isSkipWhiteSpace = true;
property = [];
continue;
}
// 处理转移字符
if (precedingBackslash) {
property.pop();
precedingBackslash = false;
isSkipWhiteSpace = true;
appendedLineBegin = true;
if (c === '\r') {
skipLF = true;
}
continue;
}
// 解析出配置项
// 进行校验
if (!validateProperty(property)) {
return false;
}
hasProperty = true;
property = [];
isNewLine = true;
isSkipWhiteSpace = true;
}
// 校验最后一行
if (property.length > 0 && !isCommentLine) {
return validateProperty(property);
}
return hasProperty;
},
/**

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,11 +16,11 @@
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.common.AuthSystemTypes;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.console.security.nacos.NacosAuthManager;
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
import com.alibaba.nacos.core.auth.AccessException;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.auth.AuthSystemTypes;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Before;
import org.junit.Test;

Some files were not shown because too many files have changed in this diff Show More