diff --git a/auth/pom.xml b/auth/pom.xml
index fae96dff4..ef110818c 100644
--- a/auth/pom.xml
+++ b/auth/pom.xml
@@ -59,21 +59,6 @@
org.apache.tomcat.embed
tomcat-embed-core
-
-
- io.jsonwebtoken
- jjwt-api
-
-
- io.jsonwebtoken
- jjwt-impl
- runtime
-
-
- io.jsonwebtoken
- jjwt-jackson
- runtime
-
diff --git a/auth/src/main/java/com/alibaba/nacos/auth/config/AuthConfigs.java b/auth/src/main/java/com/alibaba/nacos/auth/config/AuthConfigs.java
index cd47d7556..ba7929da1 100644
--- a/auth/src/main/java/com/alibaba/nacos/auth/config/AuthConfigs.java
+++ b/auth/src/main/java/com/alibaba/nacos/auth/config/AuthConfigs.java
@@ -16,23 +16,24 @@
package com.alibaba.nacos.auth.config;
-import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.common.JustForTest;
import com.alibaba.nacos.common.event.ServerConfigChangeEvent;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.ConvertUtils;
+import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.sys.env.EnvUtil;
-import io.jsonwebtoken.io.Decoders;
-import io.jsonwebtoken.io.DecodingException;
+import com.alibaba.nacos.sys.utils.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
-import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
+import java.util.Properties;
/**
* Auth related configurations.
@@ -46,6 +47,8 @@ public class AuthConfigs extends Subscriber {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthConfigs.class);
+ private static final String PREFIX = "nacos.core.auth.plugin";
+
@JustForTest
private static Boolean cachingEnabled = null;
@@ -55,23 +58,6 @@ public class AuthConfigs extends Subscriber {
@Value("${" + Constants.Auth.NACOS_CORE_AUTH_ENABLED + ":false}")
private boolean authEnabled;
- /**
- * secret key.
- */
- @Value("${" + Constants.Auth.NACOS_CORE_AUTH_DEFAULT_TOKEN_SECRET_KEY + ":}")
- private String secretKey;
-
- /**
- * secret key byte array.
- */
- private byte[] secretKeyBytes;
-
- /**
- * Token validity time(seconds).
- */
- @Value("${" + Constants.Auth.NACOS_CORE_AUTH_DEFAULT_TOKEN_EXPIRE_SECONDS + ":18000}")
- private long tokenValidityInSeconds;
-
/**
* Which auth system is in use.
*/
@@ -87,24 +73,30 @@ public class AuthConfigs extends Subscriber {
@Value("${" + Constants.Auth.NACOS_CORE_AUTH_ENABLE_USER_AGENT_AUTH_WHITE + ":false}")
private boolean enableUserAgentAuthWhite;
+ private Map authPluginProperties = new HashMap<>();
+
public AuthConfigs() {
NotifyCenter.registerSubscriber(this);
+ refreshPluginProperties();
}
- public byte[] getSecretKeyBytes() {
- if (secretKeyBytes == null) {
- try {
- secretKeyBytes = Decoders.BASE64.decode(secretKey);
- } catch (DecodingException e) {
- secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
+ private void refreshPluginProperties() {
+ try {
+ Map newProperties = new HashMap<>();
+ Properties properties = PropertiesUtil.getPropertiesWithPrefix(EnvUtil.getEnvironment(), PREFIX);
+ for (String each : properties.stringPropertyNames()) {
+ int typeIndex = each.indexOf('.');
+ String type = each.substring(0, typeIndex);
+ if (!newProperties.containsKey(type)) {
+ newProperties.put(type, new Properties());
+ }
+ String subKey = each.substring(typeIndex + 1);
+ newProperties.get(type).setProperty(subKey, properties.getProperty(each));
}
-
+ authPluginProperties = newProperties;
+ } catch (Exception e) {
+ LOGGER.warn("Refresh plugin properties failed ", e);
}
- return secretKeyBytes;
- }
-
- public long getTokenValidityInSeconds() {
- return tokenValidityInSeconds;
}
public String getNacosAuthSystemType() {
@@ -141,8 +133,15 @@ public class AuthConfigs extends Subscriber {
if (Objects.nonNull(AuthConfigs.cachingEnabled)) {
return cachingEnabled;
}
- return ConvertUtils.toBoolean(
- EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_CACHING_ENABLED, "true"));
+ return ConvertUtils.toBoolean(EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_CACHING_ENABLED, "true"));
+ }
+
+ public Properties getAuthPluginProperties(String authType) {
+ if (!authPluginProperties.containsKey(authType)) {
+ LOGGER.warn("Can't find properties for type {}, will use empty properties", authType);
+ return new Properties();
+ }
+ return authPluginProperties.get(authType);
}
@JustForTest
@@ -154,14 +153,13 @@ public class AuthConfigs extends Subscriber {
public void onEvent(ServerConfigChangeEvent event) {
try {
authEnabled = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_ENABLED, Boolean.class, false);
- cachingEnabled = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_CACHING_ENABLED, Boolean.class,
- true);
+ cachingEnabled = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_CACHING_ENABLED, Boolean.class, true);
serverIdentityKey = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_KEY, "");
serverIdentityValue = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_VALUE, "");
- enableUserAgentAuthWhite = EnvUtil.getProperty(
- Constants.Auth.NACOS_CORE_AUTH_ENABLE_USER_AGENT_AUTH_WHITE, Boolean.class,
- false);
+ enableUserAgentAuthWhite = EnvUtil
+ .getProperty(Constants.Auth.NACOS_CORE_AUTH_ENABLE_USER_AGENT_AUTH_WHITE, Boolean.class, false);
nacosAuthSystemType = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SYSTEM_TYPE, "");
+ refreshPluginProperties();
} catch (Exception e) {
LOGGER.warn("Upgrade auth config from env failed, use old value", e);
}
diff --git a/auth/src/test/java/com/alibaba/nacos/auth/config/AuthConfigsTest.java b/auth/src/test/java/com/alibaba/nacos/auth/config/AuthConfigsTest.java
index 73014398b..94db1a2ce 100644
--- a/auth/src/test/java/com/alibaba/nacos/auth/config/AuthConfigsTest.java
+++ b/auth/src/test/java/com/alibaba/nacos/auth/config/AuthConfigsTest.java
@@ -44,6 +44,7 @@ public class AuthConfigsTest {
public void setUp() throws Exception {
environment = new MockEnvironment();
EnvUtil.setEnvironment(environment);
+ environment.setProperty("nacos.core.auth.plugin.test.key", "test");
authConfigs = new AuthConfigs();
}
diff --git a/console/src/main/resources/application.properties b/console/src/main/resources/application.properties
index 5880d1f69..ed3054bef 100644
--- a/console/src/main/resources/application.properties
+++ b/console/src/main/resources/application.properties
@@ -120,16 +120,6 @@ nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
-### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
-# nacos.core.auth.ldap.url=ldap://localhost:389
-# nacos.core.auth.ldap.userdn=cn={0},ou=user,dc=company,dc=com
-
-### The token expiration in seconds:
-nacos.core.auth.default.token.expire.seconds=18000
-
-### The default token:
-nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
-
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
@@ -141,8 +131,15 @@ nacos.core.auth.enable.userAgentAuthWhite=false
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
-### authority key in request:
-nacos.core.auth.authorityKey=authority,username,password
+### worked when nacos.core.auth.system.type=nacos
+### The token expiration in seconds:
+nacos.core.auth.plugin.nacos.token.expire.seconds=18000
+### The default token:
+nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
+
+### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
+# nacos.core.auth.ldap.url=ldap://localhost:389
+# nacos.core.auth.ldap.userdn=cn={0},ou=user,dc=company,dc=com
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
diff --git a/distribution/conf/application.properties b/distribution/conf/application.properties
index 522d5776d..ee46edf52 100644
--- a/distribution/conf/application.properties
+++ b/distribution/conf/application.properties
@@ -146,16 +146,6 @@ nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
-### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
-# nacos.core.auth.ldap.url=ldap://localhost:389
-# nacos.core.auth.ldap.userdn=cn={0},ou=user,dc=company,dc=com
-
-### The token expiration in seconds:
-nacos.core.auth.default.token.expire.seconds=18000
-
-### The default token:
-nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
-
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
@@ -167,6 +157,16 @@ nacos.core.auth.enable.userAgentAuthWhite=false
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
+### worked when nacos.core.auth.system.type=nacos
+### The token expiration in seconds:
+nacos.core.auth.plugin.nacos.token.expire.seconds=18000
+### The default token:
+nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
+
+### worked when nacos.core.auth.system.type=ldap,{0} is Placeholder,replace login username
+# nacos.core.auth.ldap.url=ldap://localhost:389
+# nacos.core.auth.ldap.userdn=cn={0},ou=user,dc=company,dc=com
+
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
diff --git a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/JwtTokenManager.java b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/JwtTokenManager.java
index e382520d8..b3ed7123f 100644
--- a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/JwtTokenManager.java
+++ b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/JwtTokenManager.java
@@ -16,7 +16,6 @@
package com.alibaba.nacos.plugin.auth.impl;
-import com.alibaba.nacos.auth.config.AuthConfigs;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@@ -44,7 +43,7 @@ public class JwtTokenManager {
private static final String AUTHORITIES_KEY = "auth";
@Autowired
- private AuthConfigs authConfigs;
+ private NacosAuthConfig nacosAuthConfig;
/**
* Create token.
@@ -67,11 +66,12 @@ public class JwtTokenManager {
long now = System.currentTimeMillis();
Date validity;
- validity = new Date(now + authConfigs.getTokenValidityInSeconds() * 1000L);
+
+ validity = new Date(now + nacosAuthConfig.getTokenValidityInSeconds() * 1000L);
Claims claims = Jwts.claims().setSubject(userName);
return Jwts.builder().setClaims(claims).setExpiration(validity)
- .signWith(Keys.hmacShaKeyFor(authConfigs.getSecretKeyBytes()), SignatureAlgorithm.HS256).compact();
+ .signWith(Keys.hmacShaKeyFor(nacosAuthConfig.getSecretKeyBytes()), SignatureAlgorithm.HS256).compact();
}
/**
@@ -81,7 +81,7 @@ public class JwtTokenManager {
* @return auth info
*/
public Authentication getAuthentication(String token) {
- Claims claims = Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build()
+ Claims claims = Jwts.parserBuilder().setSigningKey(nacosAuthConfig.getSecretKeyBytes()).build()
.parseClaimsJws(token).getBody();
List authorities = AuthorityUtils
@@ -97,7 +97,7 @@ public class JwtTokenManager {
* @param token token
*/
public void validateToken(String token) {
- Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build().parseClaimsJws(token);
+ Jwts.parserBuilder().setSigningKey(nacosAuthConfig.getSecretKeyBytes()).build().parseClaimsJws(token);
}
}
diff --git a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthConfig.java b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthConfig.java
index 9d2368b19..57d0b4a58 100644
--- a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthConfig.java
+++ b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthConfig.java
@@ -19,9 +19,12 @@ package com.alibaba.nacos.plugin.auth.impl;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
+import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
import com.alibaba.nacos.plugin.auth.impl.filter.JwtAuthenticationTokenFilter;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.DecodingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
@@ -39,6 +42,8 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import org.springframework.web.cors.CorsUtils;
import javax.annotation.PostConstruct;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
/**
* Spring security config.
@@ -76,12 +81,36 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ControllerMethodsCache methodsCache;
+ /**
+ * secret key.
+ */
+ private String secretKey;
+
+ /**
+ * secret key byte array.
+ */
+ private byte[] secretKeyBytes;
+
+ /**
+ * Token validity time(seconds).
+ */
+ private long tokenValidityInSeconds;
+
/**
* Init.
*/
@PostConstruct
public void init() {
methodsCache.initClassMethod("com.alibaba.nacos.plugin.auth.impl.controller");
+ initProperties();
+ }
+
+ private void initProperties() {
+ Properties properties = authConfigs.getAuthPluginProperties(AuthConstants.AUTH_PLUGIN_TYPE);
+ String validitySeconds = properties
+ .getProperty(AuthConstants.TOKEN_EXPIRE_SECONDS, AuthConstants.DEFAULT_TOKEN_EXPIRE_SECONDS);
+ tokenValidityInSeconds = Long.parseLong(validitySeconds);
+ secretKey = properties.getProperty(AuthConstants.TOKEN_SECRET_KEY, AuthConstants.DEFAULT_TOKEN_SECRET_KEY);
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@@ -141,4 +170,19 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
return new BCryptPasswordEncoder();
}
+ public byte[] getSecretKeyBytes() {
+ if (secretKeyBytes == null) {
+ try {
+ secretKeyBytes = Decoders.BASE64.decode(secretKey);
+ } catch (DecodingException e) {
+ secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
+ }
+
+ }
+ return secretKeyBytes;
+ }
+
+ public long getTokenValidityInSeconds() {
+ return tokenValidityInSeconds;
+ }
}
diff --git a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthPluginService.java b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthPluginService.java
index 739224e5c..a9f55486f 100644
--- a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthPluginService.java
+++ b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/NacosAuthPluginService.java
@@ -38,8 +38,6 @@ import java.util.List;
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosAuthPluginService implements AuthPluginService {
- private static final String AUTH_PLUGIN_TYPE = "nacos";
-
private static final String USER_IDENTITY_PARAM_KEY = "user";
private static final List IDENTITY_NAMES = new LinkedList() {
@@ -77,7 +75,7 @@ public class NacosAuthPluginService implements AuthPluginService {
@Override
public String getAuthServiceName() {
- return AUTH_PLUGIN_TYPE;
+ return AuthConstants.AUTH_PLUGIN_TYPE;
}
private void checkNacosAuthManager() {
diff --git a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/constant/AuthConstants.java b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/constant/AuthConstants.java
index 07e5f9ef9..4aa02d78c 100644
--- a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/constant/AuthConstants.java
+++ b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/constant/AuthConstants.java
@@ -23,6 +23,8 @@ package com.alibaba.nacos.plugin.auth.impl.constant;
*/
public class AuthConstants {
+ public static final String AUTH_PLUGIN_TYPE = "nacos";
+
public static final String GLOBAL_ADMIN_ROLE = "ROLE_ADMIN";
public static final String AUTHORIZATION_HEADER = "Authorization";
@@ -38,4 +40,12 @@ public class AuthConstants {
public static final String UPDATE_PASSWORD_ENTRY_POINT = CONSOLE_RESOURCE_NAME_PREFIX + "user/password";
public static final String NACOS_USER_KEY = "nacosuser";
+
+ public static final String TOKEN_SECRET_KEY = "token.secret.key";
+
+ public static final String DEFAULT_TOKEN_SECRET_KEY = "";
+
+ public static final String TOKEN_EXPIRE_SECONDS = "token.expire.seconds";
+
+ public static final String DEFAULT_TOKEN_EXPIRE_SECONDS = "18000";
}
diff --git a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/UserController.java b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/UserController.java
index 14a872e36..38dc9e9c5 100644
--- a/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/UserController.java
+++ b/plugin-default-impl/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/UserController.java
@@ -25,6 +25,7 @@ import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.JwtTokenManager;
+import com.alibaba.nacos.plugin.auth.impl.NacosAuthConfig;
import com.alibaba.nacos.plugin.auth.impl.NacosAuthManager;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
@@ -82,6 +83,9 @@ public class UserController {
@Autowired
private AuthConfigs authConfigs;
+ @Autowired
+ private NacosAuthConfig nacosAuthConfig;
+
@Autowired
private NacosAuthManager authManager;
@@ -214,7 +218,7 @@ public class UserController {
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.put(Constants.ACCESS_TOKEN, user.getToken());
- result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds());
+ result.put(Constants.TOKEN_TTL, nacosAuthConfig.getTokenValidityInSeconds());
result.put(Constants.GLOBAL_ADMIN, user.isGlobalAdmin());
result.put(Constants.USERNAME, user.getUserName());
return result;
diff --git a/plugin-default-impl/src/test/java/com/alibaba/nacos/plugin/auth/impl/controller/UserControllerTest.java b/plugin-default-impl/src/test/java/com/alibaba/nacos/plugin/auth/impl/controller/UserControllerTest.java
index ac5e0a42a..209f77bf3 100644
--- a/plugin-default-impl/src/test/java/com/alibaba/nacos/plugin/auth/impl/controller/UserControllerTest.java
+++ b/plugin-default-impl/src/test/java/com/alibaba/nacos/plugin/auth/impl/controller/UserControllerTest.java
@@ -18,6 +18,7 @@ package com.alibaba.nacos.plugin.auth.impl.controller;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
+import com.alibaba.nacos.plugin.auth.impl.NacosAuthConfig;
import com.alibaba.nacos.plugin.auth.impl.NacosAuthManager;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
@@ -49,6 +50,9 @@ public class UserControllerTest {
@Mock
private AuthConfigs authConfigs;
+ @Mock
+ private NacosAuthConfig nacosAuthConfig;
+
@Mock
private NacosAuthManager authManager;
@@ -65,13 +69,14 @@ public class UserControllerTest {
user.setToken("1234567890");
injectObject("authConfigs", authConfigs);
injectObject("authManager", authManager);
+ injectObject("nacosAuthConfig", nacosAuthConfig);
}
@Test
public void testLoginWithAuthedUser() throws AccessException {
when(authManager.login(request)).thenReturn(user);
when(authConfigs.getNacosAuthSystemType()).thenReturn(AuthSystemTypes.NACOS.name());
- when(authConfigs.getTokenValidityInSeconds()).thenReturn(18000L);
+ when(nacosAuthConfig.getTokenValidityInSeconds()).thenReturn(18000L);
Object actual = userController.login("nacos", "nacos", response, request);
assertThat(actual, instanceOf(JsonNode.class));
String actualString = actual.toString();
diff --git a/sys/pom.xml b/sys/pom.xml
index 2222a4ae7..77882fedb 100644
--- a/sys/pom.xml
+++ b/sys/pom.xml
@@ -67,6 +67,10 @@
org.springframework.boot
spring-boot-test
+
+ org.codehaus.jackson
+ jackson-core-asl
+
diff --git a/sys/src/main/java/com/alibaba/nacos/sys/utils/PropertiesUtil.java b/sys/src/main/java/com/alibaba/nacos/sys/utils/PropertiesUtil.java
new file mode 100644
index 000000000..f6da571dc
--- /dev/null
+++ b/sys/src/main/java/com/alibaba/nacos/sys/utils/PropertiesUtil.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2021 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.sys.utils;
+
+import org.springframework.core.env.Environment;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Properties util.
+ *
+ * @author xiweng.yy
+ */
+public class PropertiesUtil {
+
+ public static Properties getPropertiesWithPrefix(Environment environment, String prefix)
+ throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ return handleSpringBinder(environment, prefix, Properties.class);
+ }
+
+ public static Map getPropertiesWithPrefixForMap(Environment environment, String prefix)
+ throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ return handleSpringBinder(environment, prefix, Map.class);
+ }
+
+ /**
+ * Handle spring binder to bind object.
+ *
+ * @param environment spring environment
+ * @param prefix properties prefix
+ * @param targetClass target class
+ * @param target class
+ * @return binder object
+ */
+ @SuppressWarnings("unchecked")
+ public static T handleSpringBinder(Environment environment, String prefix, Class targetClass)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
+ Class> binderClass = Class.forName("org.springframework.boot.context.properties.bind.Binder");
+ Method getMethod = binderClass.getDeclaredMethod("get", Environment.class);
+ Method bindMethod = binderClass.getDeclaredMethod("bind", String.class, Class.class);
+ Object binderObject = getMethod.invoke(null, environment);
+ String prefixParam = prefix.endsWith(".") ? prefix.substring(0, prefix.length() - 1) : prefix;
+ Object bindResultObject = bindMethod.invoke(binderObject, prefixParam, targetClass);
+ Method resultGetMethod = bindResultObject.getClass().getDeclaredMethod("get");
+ return (T) resultGetMethod.invoke(bindResultObject);
+ }
+}
diff --git a/sys/src/test/java/com/alibaba/nacos/sys/utils/PropertiesUtilTest.java b/sys/src/test/java/com/alibaba/nacos/sys/utils/PropertiesUtilTest.java
new file mode 100644
index 000000000..f0b6abbda
--- /dev/null
+++ b/sys/src/test/java/com/alibaba/nacos/sys/utils/PropertiesUtilTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999-2021 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.sys.utils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringRunner.class)
+@ActiveProfiles("prefix")
+@SpringBootTest(classes = PropertiesUtilTest.class)
+public class PropertiesUtilTest {
+
+ @Autowired
+ private ConfigurableEnvironment environment;
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testGetPropertiesWithPrefixForMap()
+ throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Map actual = PropertiesUtil.getPropertiesWithPrefixForMap(environment, "nacos.prefix");
+ assertEquals(3, actual.size());
+ for (Map.Entry entry : actual.entrySet()) {
+ String key = entry.getKey();
+ Map subMap = (Map) entry.getValue();
+ switch (key) {
+ case "one":
+ assertEquals("1", subMap.get("value"));
+ break;
+ case "two":
+ assertEquals("2", subMap.get("value"));
+ break;
+ case "three":
+ assertEquals("3", subMap.get("value"));
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ @Test
+ public void testGetPropertiesWithPrefix()
+ throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Properties actual = PropertiesUtil.getPropertiesWithPrefix(environment, "nacos.prefix");
+ assertEquals(3, actual.size());
+ }
+}
diff --git a/sys/src/test/resources/application-prefix.properties b/sys/src/test/resources/application-prefix.properties
new file mode 100644
index 000000000..f1c8950f2
--- /dev/null
+++ b/sys/src/test/resources/application-prefix.properties
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+nacos.prefix.one.value=1
+nacos.prefix.two.value=2
+nacos.prefix.three.value=3
+nacos.other.prefix.one.value=1