V3.0 develop console mode (#13134)

* Use Page to replace List result for some maintainer api.

* Support namespace page.

* uniform Namespace model to api。

* Support console get server state from nacos-server

* Fix update namespace invalid problem.

* console support setting admin password.

* Add Console maintainer client auth plugin to support identity request.

* Support Nacos Console get users info from nacos server.

* Support Nacos Console get role and permission info from nacos server.

* Fix NPE by AuthConfig loading Circular Dependencies.
This commit is contained in:
杨翊 SionYang 2025-02-25 18:27:01 +08:00 committed by GitHub
parent f127fea599
commit 2c025e20ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
109 changed files with 2272 additions and 1423 deletions

View File

@ -190,6 +190,9 @@ nacos.console.port=8080
### Nacos Server Web context path:
nacos.console.contextPath=
### Nacos Server context path, which link to nacos server `nacos.server.contextPath`, works when deployment type is `console`
nacos.console.remote.server.context-path=/nacos
#************** Console UI Configuration ***************#
### Turn on/off the nacos console ui.

View File

@ -16,10 +16,10 @@
package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.config.server.constant.PropertiesConstant;
import com.alibaba.nacos.config.server.service.repository.ConfigInfoPersistService;
import com.alibaba.nacos.core.namespace.injector.AbstractNamespaceDetailInjector;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.springframework.stereotype.Service;

View File

@ -19,7 +19,7 @@ package com.alibaba.nacos.config.server.service;
import com.alibaba.nacos.config.server.constant.PropertiesConstant;
import com.alibaba.nacos.config.server.model.capacity.TenantCapacity;
import com.alibaba.nacos.config.server.service.repository.ConfigInfoPersistService;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

View File

@ -94,6 +94,7 @@ class EditorNameSpace extends React.Component {
handleSubmit() {
const { locale = {} } = this.props;
this.field.validate((errors, values) => {
console.log(values);
if (errors) {
return;
}

View File

@ -28,7 +28,10 @@ request.middleWare((_config = {}) => {
let config = _config;
let { url = '' } = config;
const namespace = localStorage.getItem('namespace') ? localStorage.getItem('namespace') : '';
let namespace = config?.data?.namespaceId;
if (!namespace) {
namespace = localStorage.getItem('namespace') ? localStorage.getItem('namespace') : '';
}
// 如果url中已经有 namespaceId, 不在data中添加namespaceId
config.data =
url.indexOf('namespaceId=') === -1

View File

@ -20,6 +20,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Nacos console starter.
@ -28,6 +29,7 @@ import org.springframework.context.annotation.PropertySource;
*/
@SpringBootApplication(exclude = LdapAutoConfiguration.class)
@PropertySource("classpath:nacos-console.properties")
@EnableScheduling
public class NacosConsole {
public static void main(String[] args) {

View File

@ -19,11 +19,6 @@ package com.alibaba.nacos.console.config;
import com.alibaba.nacos.console.handler.impl.remote.EnabledRemoteHandler;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.naming.selector.SelectorManager;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -45,44 +40,4 @@ public class ConsoleDeploymentConfig {
public SelectorManager selectorManager() {
return new SelectorManager();
}
@Bean
public IAuthenticationManager authenticationManager() {
// TODO implement remote authentication manager.
return new IAuthenticationManager() {
@Override
public NacosUser authenticate(String username, String rawPassword) throws AccessException {
return new NacosUser("nacos");
}
@Override
public NacosUser authenticate(String jwtToken) throws AccessException {
return new NacosUser("nacos");
}
@Override
public NacosUser authenticate(HttpServletRequest httpServletRequest) throws AccessException {
return new NacosUser("nacos");
}
@Override
public void authorize(Permission permission, NacosUser nacosUser) throws AccessException {
}
@Override
public boolean hasGlobalAdminRole(String username) {
return true;
}
@Override
public boolean hasGlobalAdminRole() {
return true;
}
@Override
public boolean hasGlobalAdminRole(NacosUser nacosUser) {
return true;
}
};
}
}

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.console.config;
import com.alibaba.nacos.auth.config.NacosAuthConfig;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.config.AbstractDynamicConfig;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
import com.alibaba.nacos.plugin.auth.constant.Constants;
@ -41,6 +42,10 @@ public class NacosConsoleAuthConfig extends AbstractDynamicConfig implements Nac
*/
private String nacosAuthSystemType;
private String serverIdentityKey;
private String serverIdentityValue;
public NacosConsoleAuthConfig() {
super("NacosConsoleAuth");
resetConfig();
@ -63,23 +68,25 @@ public class NacosConsoleAuthConfig extends AbstractDynamicConfig implements Nac
@Override
public boolean isSupportServerIdentity() {
return false;
return StringUtils.isNotBlank(serverIdentityKey) && StringUtils.isNotBlank(serverIdentityValue);
}
@Override
public String getServerIdentityKey() {
return "";
return serverIdentityKey;
}
@Override
public String getServerIdentityValue() {
return "";
return serverIdentityValue;
}
@Override
protected void getConfigFromEnv() {
authEnabled = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_CONSOLE_ENABLED, Boolean.class, true);
nacosAuthSystemType = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SYSTEM_TYPE, "");
serverIdentityKey = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_KEY, "");
serverIdentityValue = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_VALUE, "");
}
@Override

View File

@ -17,41 +17,41 @@
package com.alibaba.nacos.console.config;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.console.handler.impl.inner.EnabledInnerHandler;
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.controller.v3.PermissionControllerV3;
import com.alibaba.nacos.plugin.auth.impl.controller.v3.RoleControllerV3;
import com.alibaba.nacos.plugin.auth.impl.controller.v3.UserControllerV3;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Configuration of console auth controller.
* TODO use {@link Import} to dynamic load auth plugin controller like Mybatis.
*
* @author xiweng.yy
*/
@Configuration
@EnabledInnerHandler
public class NacosConsoleAuthControllerConfig {
@Bean
public UserControllerV3 consoleUserControllerV3(NacosUserDetailsServiceImpl userDetailsService,
NacosRoleServiceImpl roleService, AuthConfigs authConfigs, IAuthenticationManager iAuthenticationManager,
public UserControllerV3 consoleUserControllerV3(NacosUserService userDetailsService, NacosRoleService roleService,
AuthConfigs authConfigs, IAuthenticationManager iAuthenticationManager,
TokenManagerDelegate jwtTokenManager) {
return new UserControllerV3(userDetailsService, roleService, authConfigs, iAuthenticationManager,
jwtTokenManager);
}
@Bean
public RoleControllerV3 consoleRoleControllerV3(NacosRoleServiceImpl roleService) {
public RoleControllerV3 consoleRoleControllerV3(NacosRoleService roleService) {
return new RoleControllerV3(roleService);
}
@Bean
public PermissionControllerV3 permissionControllerV3(NacosRoleServiceImpl roleService) {
public PermissionControllerV3 permissionControllerV3(NacosRoleService roleService) {
return new PermissionControllerV3(roleService);
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 1999-2025 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.console.config;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.console.handler.impl.remote.EnabledRemoteHandler;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.plugin.auth.impl.authenticate.DefaultAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceRemoteImpl;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManager;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.token.impl.CachedJwtTokenManager;
import com.alibaba.nacos.plugin.auth.impl.token.impl.JwtTokenManager;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserServiceRemoteImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import javax.annotation.PostConstruct;
/**
* Configuration of console auth service.
* TODO use {@link Import} to dynamic load auth plugin controller like Mybatis.
*
* @author xiweng.yy
*/
@EnabledRemoteHandler
@Import(AuthConfigs.class)
@Configuration
public class NacosConsoleAuthServiceConfig {
private final ControllerMethodsCache methodsCache;
public NacosConsoleAuthServiceConfig(ControllerMethodsCache methodsCache) {
this.methodsCache = methodsCache;
}
@PostConstruct
public void registerAuthPathToCache() {
methodsCache.initClassMethod("com.alibaba.nacos.plugin.auth.impl.controller");
}
@Bean
public NacosRoleService nacosRoleService(AuthConfigs authConfigs) {
return new NacosRoleServiceRemoteImpl(authConfigs);
}
@Bean
public NacosUserService nacosUserService(AuthConfigs authConfigs) {
return new NacosUserServiceRemoteImpl(authConfigs);
}
@Bean
@ConditionalOnMissingBean
public IAuthenticationManager defaultAuthenticationManager(NacosUserService userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleService roleService) {
return new DefaultAuthenticationManager(userDetailsService, jwtTokenManager, roleService);
}
@Bean
@ConditionalOnProperty(value = TokenManagerDelegate.NACOS_AUTH_TOKEN_CACHING_ENABLED, havingValue = "false", matchIfMissing = true)
public TokenManager tokenManager(AuthConfigs authConfigs) {
return new JwtTokenManager(authConfigs);
}
@Bean
@ConditionalOnProperty(value = TokenManagerDelegate.NACOS_AUTH_TOKEN_CACHING_ENABLED, havingValue = "true")
public TokenManager cachedTokenManager(AuthConfigs authConfigs) {
return new CachedJwtTokenManager(new JwtTokenManager(authConfigs));
}
@Bean
public TokenManagerDelegate tokenManagerDelegate(TokenManager tokenManager) {
return new TokenManagerDelegate(tokenManager);
}
}

View File

@ -24,7 +24,7 @@ import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.console.handler.impl.inner.EnabledInnerHandler;
import com.alibaba.nacos.console.paramcheck.ConsoleDefaultHttpParamExtractor;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.core.service.NamespaceOperationService;

View File

@ -18,13 +18,13 @@ package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.console.handler.impl.inner.EnabledInnerHandler;
import com.alibaba.nacos.console.paramcheck.ConsoleDefaultHttpParamExtractor;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.core.service.NacosServerStateService;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import com.alibaba.nacos.sys.utils.DiskUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@ -33,7 +33,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.common.utils.StringUtils.FOLDER_SEPARATOR;
@ -48,12 +47,19 @@ import static com.alibaba.nacos.common.utils.StringUtils.WINDOWS_FOLDER_SEPARATO
@RestController
@RequestMapping("/v1/console/server")
@ExtractorManager.Extractor(httpExtractor = ConsoleDefaultHttpParamExtractor.class)
@EnabledInnerHandler
public class ServerStateController {
private static final String ANNOUNCEMENT_FILE = "announcement.conf";
private static final String GUIDE_FILE = "console-guide.conf";
private final NacosServerStateService stateService;
public ServerStateController(NacosServerStateService stateService) {
this.stateService = stateService;
}
/**
* Get server state of current server.
*
@ -62,11 +68,7 @@ public class ServerStateController {
@GetMapping("/state")
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/console/server/state")
public ResponseEntity<Map<String, String>> serverState() {
Map<String, String> serverState = new HashMap<>(4);
for (ModuleState each : ModuleStateHolder.getInstance().getAllModuleStates()) {
each.getStates().forEach((s, o) -> serverState.put(s, null == o ? null : o.toString()));
}
return ResponseEntity.ok().body(serverState);
return ResponseEntity.ok(stateService.getServerState());
}
@GetMapping("/announcement")

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.console.controller.v2;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
@ -26,7 +27,6 @@ import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.console.handler.impl.inner.EnabledInnerHandler;
import com.alibaba.nacos.console.paramcheck.ConsoleDefaultHttpParamExtractor;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;

View File

@ -18,6 +18,7 @@
package com.alibaba.nacos.console.controller.v3;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.api.model.v2.SupportedLanguage;
import com.alibaba.nacos.console.paramcheck.ConsoleDefaultHttpParamExtractor;
@ -54,7 +55,7 @@ public class ConsoleServerStateController {
* @return state json.
*/
@GetMapping("/state")
public ResponseEntity<Map<String, String>> serverState() {
public ResponseEntity<Map<String, String>> serverState() throws NacosException {
Map<String, String> serverState = serverStateProxy.getServerState();
return ResponseEntity.ok().body(serverState);
}

View File

@ -24,7 +24,7 @@ import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.console.paramcheck.ConsoleDefaultHttpParamExtractor;
import com.alibaba.nacos.console.proxy.core.NamespaceProxy;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.form.CreateNamespaceForm;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;

View File

@ -20,12 +20,14 @@ package com.alibaba.nacos.console.controller.v3.naming;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.builder.InstanceBuilder;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.console.proxy.naming.InstanceProxy;
import com.alibaba.nacos.core.control.TpsControl;
import com.alibaba.nacos.core.model.form.PageForm;
@ -76,10 +78,13 @@ public class ConsoleInstanceController {
@RequestMapping("/list")
public Result<ObjectNode> getInstanceList(InstanceListForm instanceForm, PageForm pageForm) throws NacosException {
instanceForm.validate();
// TODO use Page + List<Instance> replace with console ui
ObjectNode result = instanceProxy.listInstances(instanceForm.getNamespaceId(), instanceForm.getServiceName(),
instanceForm.getGroupName(), instanceForm.getClusterName(), pageForm.getPageNo(),
pageForm.getPageSize());
Page<? extends Instance> instancePage = instanceProxy.listInstances(instanceForm.getNamespaceId(),
instanceForm.getServiceName(), instanceForm.getGroupName(), instanceForm.getClusterName(),
pageForm.getPageNo(), pageForm.getPageSize());
// TODO use Page<? extends Instance> directly after console-ui modified
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.replace("instances", JacksonUtils.transferToJsonNode(instancePage.getPageItems()));
result.put("count", instancePage.getTotalCount());
return Result.success(result);
}

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.console.handler;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.Result;
/**
@ -30,7 +31,8 @@ public interface HealthHandler {
* Perform readiness check to determine if Nacos is ready to handle requests.
*
* @return readiness result
* @throws NacosException if an error occurs during readiness check
*/
Result<String> checkReadiness();
Result<String> checkReadiness() throws NacosException;
}

View File

@ -17,6 +17,8 @@
package com.alibaba.nacos.console.handler;
import com.alibaba.nacos.api.exception.NacosException;
import java.util.Map;
/**
@ -30,8 +32,9 @@ public interface ServerStateHandler {
* Get the current state of the server.
*
* @return a map containing the server state
* @throws NacosException if an error occurs while retrieving the server state
*/
Map<String, String> getServerState();
Map<String, String> getServerState() throws NacosException;
/**
* Get the announcement content based on the language.

View File

@ -18,7 +18,7 @@
package com.alibaba.nacos.console.handler.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import java.util.List;

View File

@ -17,11 +17,9 @@
package com.alibaba.nacos.console.handler.impl.inner;
import com.alibaba.nacos.console.handler.impl.AbstractServerStateHandler;
import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import com.alibaba.nacos.core.service.NacosServerStateService;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
@ -33,12 +31,14 @@ import java.util.Map;
@EnabledInnerHandler
public class ServerStateInnerHandler extends AbstractServerStateHandler {
private final NacosServerStateService stateService;
public ServerStateInnerHandler(NacosServerStateService stateService) {
this.stateService = stateService;
}
public Map<String, String> getServerState() {
Map<String, String> serverState = new HashMap<>(4);
for (ModuleState each : ModuleStateHolder.getInstance().getAllModuleStates()) {
each.getStates().forEach((s, o) -> serverState.put(s, null == o ? null : o.toString()));
}
return serverState;
return stateService.getServerState();
}
}

View File

@ -21,7 +21,7 @@ import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.console.handler.core.NamespaceHandler;
import com.alibaba.nacos.console.handler.impl.inner.EnabledInnerHandler;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;
import com.alibaba.nacos.core.service.NamespaceOperationService;

View File

@ -17,18 +17,18 @@
package com.alibaba.nacos.console.handler.impl.inner.naming;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.trace.event.naming.UpdateInstanceTraceEvent;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.console.handler.impl.inner.EnabledInnerHandler;
import com.alibaba.nacos.console.handler.naming.InstanceHandler;
import com.alibaba.nacos.core.utils.PageUtil;
import com.alibaba.nacos.naming.core.CatalogService;
import com.alibaba.nacos.naming.core.CatalogServiceV2Impl;
import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl;
import com.alibaba.nacos.naming.model.form.InstanceForm;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Service;
import java.util.List;
@ -42,7 +42,7 @@ import java.util.List;
@EnabledInnerHandler
public class InstanceInnerHandler implements InstanceHandler {
private final CatalogServiceV2Impl catalogServiceV2;
private final CatalogService catalogService;
private final InstanceOperatorClientImpl instanceServiceV2;
@ -52,20 +52,16 @@ public class InstanceInnerHandler implements InstanceHandler {
* @param catalogServiceV2 the service for catalog-related operations
*/
public InstanceInnerHandler(CatalogServiceV2Impl catalogServiceV2, InstanceOperatorClientImpl instanceServiceV2) {
this.catalogServiceV2 = catalogServiceV2;
this.catalogService = catalogServiceV2;
this.instanceServiceV2 = instanceServiceV2;
}
@Override
public ObjectNode listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName, String clusterName, int page,
int pageSize) throws NacosException {
List<? extends Instance> instances = catalogServiceV2.listInstances(namespaceId, groupName,
public Page<? extends Instance> listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName,
String clusterName, int page, int pageSize) throws NacosException {
List<? extends Instance> instances = catalogService.listInstances(namespaceId, groupName,
serviceNameWithoutGroup, clusterName);
List<? extends Instance> resultInstances = PageUtil.subPageList(instances, page, pageSize);
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.replace("instances", JacksonUtils.transferToJsonNode(resultInstances));
result.put("count", instances.size());
return result;
return PageUtil.subPage(instances, page, pageSize);
}
@Override

View File

@ -0,0 +1,66 @@
/*
* Copyright 1999-2025 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.console.handler.impl.remote;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.auth.config.NacosAuthConfigHolder;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.console.config.NacosConsoleAuthConfig;
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
import com.alibaba.nacos.plugin.auth.api.RequestResource;
import com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService;
import java.util.List;
import java.util.Properties;
/**
* Client Auth Plugin implementation for console remote maintainer client.
*
* @author xiweng.yy
*/
public class ConsoleMaintainerClientAuthPlugin extends AbstractClientAuthService {
private LoginIdentityContext identityContext = new LoginIdentityContext();
@Override
public Boolean login(Properties properties) {
NacosConsoleAuthConfig authConfig = (NacosConsoleAuthConfig) NacosAuthConfigHolder.getInstance()
.getNacosAuthConfigByScope(NacosConsoleAuthConfig.NACOS_CONSOLE_AUTH_SCOPE);
if (authConfig.isSupportServerIdentity()) {
identityContext.setParameter(authConfig.getServerIdentityKey(), authConfig.getServerIdentityValue());
}
return true;
}
@Override
public void setServerList(List<String> serverList) {
}
@Override
public void setNacosRestTemplate(NacosRestTemplate nacosRestTemplate) {
}
@Override
public LoginIdentityContext getLoginIdentityContext(RequestResource resource) {
return identityContext;
}
@Override
public void shutdown() throws NacosException {
}
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.console.handler.impl.remote;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.console.handler.HealthHandler;
import org.springframework.stereotype.Service;
@ -29,10 +30,16 @@ import org.springframework.stereotype.Service;
@EnabledRemoteHandler
public class HealthRemoteHandler implements HealthHandler {
private final NacosMaintainerClientHolder clientHolder;
public HealthRemoteHandler(NacosMaintainerClientHolder clientHolder) {
this.clientHolder = clientHolder;
}
@Override
public Result<String> checkReadiness() {
// TODO call nacos servers
return Result.success("ok");
public Result<String> checkReadiness() throws NacosException {
Boolean result = clientHolder.getNamingMaintainerService().readiness();
return result ? Result.success("ok") : Result.failure("Nacos server readiness failed.");
}
}

View File

@ -51,7 +51,6 @@ public class NacosMaintainerClientHolder {
String memberAddressString = StringUtils.join(memberAddress, ",");
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, memberAddressString);
// TODO Add admin user and pass
namingMaintainerService = NamingMaintainerFactory.createNamingMaintainerService(properties);
configMaintainerService = ConfigMaintainerFactory.createConfigMaintainerService(properties);
// TODO sub member change event to upgrade maintainer client server members.

View File

@ -16,7 +16,7 @@
package com.alibaba.nacos.console.handler.impl.remote;
import com.alibaba.nacos.common.utils.VersionUtils;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.console.handler.impl.AbstractServerStateHandler;
import com.alibaba.nacos.sys.env.Constants;
import com.alibaba.nacos.sys.env.EnvUtil;
@ -24,7 +24,6 @@ import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
@ -36,13 +35,14 @@ import java.util.Map;
@EnabledRemoteHandler
public class ServerStateRemoteHandler extends AbstractServerStateHandler {
public Map<String, String> getServerState() {
Map<String, String> serverState = new HashMap<>(4);
// TODO get state from nacos servers
// Mock first
serverState.put(Constants.STARTUP_MODE_STATE, EnvUtil.STANDALONE_MODE_ALONE);
serverState.put(Constants.FUNCTION_MODE_STATE, EnvUtil.getFunctionMode());
serverState.put(Constants.NACOS_VERSION, VersionUtils.version);
private final NacosMaintainerClientHolder clientHolder;
public ServerStateRemoteHandler(NacosMaintainerClientHolder clientHolder) {
this.clientHolder = clientHolder;
}
public Map<String, String> getServerState() throws NacosException {
Map<String, String> serverState = this.clientHolder.getNamingMaintainerService().getServerState();
serverState.put(Constants.SERVER_PORT_STATE, EnvUtil.getProperty("nacos.console.port", "8080"));
// Add current console states
for (ModuleState each : ModuleStateHolder.getInstance().getAllModuleStates()) {

View File

@ -17,15 +17,13 @@
package com.alibaba.nacos.console.handler.impl.remote.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.console.handler.core.NamespaceHandler;
import com.alibaba.nacos.console.handler.impl.remote.EnabledRemoteHandler;
import com.alibaba.nacos.console.handler.impl.remote.NacosMaintainerClientHolder;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -45,32 +43,12 @@ public class NamespaceRemoteHandler implements NamespaceHandler {
@Override
public List<Namespace> getNamespaceList() throws NacosException {
return transferToNamespaceList(clientHolder.getNamingMaintainerService().getNamespaceList());
}
private List<Namespace> transferToNamespaceList(List<com.alibaba.nacos.api.model.response.Namespace> namespaceList) {
if (null == namespaceList) {
return Collections.emptyList();
}
List<Namespace> result = new ArrayList<>();
namespaceList.forEach(namespace -> result.add(transferToNamespace(namespace)));
return result;
return clientHolder.getNamingMaintainerService().getNamespaceList();
}
@Override
public Namespace getNamespaceDetail(String namespaceId) throws NacosException {
return transferToNamespace(clientHolder.getNamingMaintainerService().getNamespace(namespaceId));
}
private Namespace transferToNamespace(com.alibaba.nacos.api.model.response.Namespace namespace) {
Namespace targetNamespace = new Namespace();
targetNamespace.setNamespaceShowName(namespace.getNamespaceShowName());
targetNamespace.setNamespaceDesc(namespace.getNamespaceDesc());
targetNamespace.setNamespace(namespace.getNamespace());
targetNamespace.setQuota(namespace.getQuota());
targetNamespace.setConfigCount(namespace.getConfigCount());
targetNamespace.setType(namespace.getType());
return targetNamespace;
return clientHolder.getNamingMaintainerService().getNamespace(namespaceId);
}
@Override
@ -81,8 +59,9 @@ public class NamespaceRemoteHandler implements NamespaceHandler {
@Override
public Boolean updateNamespace(NamespaceForm namespaceForm) throws NacosException {
return clientHolder.getNamingMaintainerService().updateNamespace(namespaceForm.getNamespaceId(),
namespaceForm.getNamespaceName(), namespaceForm.getNamespaceDesc());
return clientHolder.getNamingMaintainerService()
.updateNamespace(namespaceForm.getNamespaceId(), namespaceForm.getNamespaceName(),
namespaceForm.getNamespaceDesc());
}
@Override

View File

@ -17,14 +17,13 @@
package com.alibaba.nacos.console.handler.impl.remote.naming;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.console.handler.impl.remote.EnabledRemoteHandler;
import com.alibaba.nacos.console.handler.impl.remote.NacosMaintainerClientHolder;
import com.alibaba.nacos.console.handler.naming.InstanceHandler;
import com.alibaba.nacos.core.utils.PageUtil;
import com.alibaba.nacos.naming.model.form.InstanceForm;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Service;
import java.util.List;
@ -45,15 +44,11 @@ public class InstanceRemoteHandler implements InstanceHandler {
}
@Override
public ObjectNode listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName,
public Page<? extends Instance> listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName,
String clusterName, int page, int pageSize) throws NacosException {
List<Instance> instances = clientHolder.getNamingMaintainerService()
.listInstances(namespaceId, groupName, serviceNameWithoutGroup, clusterName, false);
List<? extends Instance> resultInstances = PageUtil.subPageList(instances, page, pageSize);
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.replace("instances", JacksonUtils.transferToJsonNode(resultInstances));
result.put("count", instances.size());
return result;
return PageUtil.subPage(instances, page, pageSize);
}
@Override

View File

@ -18,9 +18,9 @@
package com.alibaba.nacos.console.handler.naming;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.naming.model.form.InstanceForm;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* Interface for handling instance-related operations.
@ -38,10 +38,10 @@ public interface InstanceHandler {
* @param clusterName the cluster name
* @param page the page number
* @param pageSize the size of the page
* @return a JSON node containing the instances information
* @return the page object of {@link Instance}
* @throws NacosException if the list operation fails
*/
ObjectNode listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName, String clusterName,
Page<? extends Instance> listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName, String clusterName,
int page, int pageSize) throws NacosException;
/**

View File

@ -96,7 +96,7 @@ public interface ServiceHandler {
* @param serviceName the service name
* @param groupName the group name
* @param ignoreEmptyService whether to filter services with empty instances
* @return if withInstances is {@code true}, return List of {@link ServiceDetailInfo}, otherwise return List of {@link ServiceView}
* @return if withInstances is {@code true}, return Page of {@link ServiceDetailInfo}, otherwise return Page of {@link ServiceView}
* @throws NacosException if an error occurs during fetching service details
*/
Object getServiceList(boolean withInstances, String namespaceId, int pageNo, int pageSize, String serviceName,

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.console.proxy;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.console.handler.HealthHandler;
import org.springframework.stereotype.Service;
@ -40,7 +41,7 @@ public class HealthProxy {
*
* @return readiness result
*/
public Result<String> checkReadiness() {
public Result<String> checkReadiness() throws NacosException {
return healthHandler.checkReadiness();
}
}

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.console.proxy;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.console.handler.ServerStateHandler;
import org.springframework.stereotype.Service;
@ -41,7 +42,7 @@ public class ServerStateProxy {
*
* @return the server state as a Map
*/
public Map<String, String> getServerState() {
public Map<String, String> getServerState() throws NacosException {
return serverStateHandler.getServerState();
}

View File

@ -19,7 +19,7 @@ package com.alibaba.nacos.console.proxy.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.console.handler.core.NamespaceHandler;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import org.springframework.stereotype.Service;

View File

@ -18,10 +18,10 @@
package com.alibaba.nacos.console.proxy.naming;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.console.handler.naming.InstanceHandler;
import com.alibaba.nacos.naming.model.form.InstanceForm;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Service;
/**
@ -52,11 +52,11 @@ public class InstanceProxy {
* @param clusterName the cluster name
* @param page the page number
* @param pageSize the size of the page
* @return a JSON node containing the instances information
* @return the page object of {@link Instance}
* @throws IllegalArgumentException if the deployment type is invalid
* @throws NacosException if the list operation fails
*/
public ObjectNode listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName,
public Page<? extends Instance> listInstances(String namespaceId, String serviceNameWithoutGroup, String groupName,
String clusterName, int page, int pageSize) throws NacosException {
return instanceHandler.listInstances(namespaceId, serviceNameWithoutGroup, groupName, clusterName, page,
pageSize);

View File

@ -128,15 +128,17 @@ public class ServiceProxy {
public Object getServiceList(boolean withInstances, String namespaceId, int pageNo, int pageSize,
String serviceName, String groupName, boolean hasIpCount) throws NacosException {
if (withInstances) {
return serviceHandler.getServiceList(withInstances, namespaceId, pageNo, pageSize, serviceName, groupName,
hasIpCount);
// TODO use result directly after console ui changed and return page object
Page<ServiceDetailInfo> serviceDetailInfoPage = (Page<ServiceDetailInfo>) serviceHandler.getServiceList(
withInstances, namespaceId, pageNo, pageSize, serviceName, groupName, hasIpCount);
return serviceDetailInfoPage.getPageItems();
}
// TODO use result directly after console ui changed and return page object
List<ServiceView> views = (List<ServiceView>) serviceHandler.getServiceList(withInstances, namespaceId, pageNo,
Page<ServiceView> views = (Page<ServiceView>) serviceHandler.getServiceList(withInstances, namespaceId, pageNo,
pageSize, serviceName, groupName, hasIpCount);
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.put(FieldsConstants.COUNT, views.size());
result.set(FieldsConstants.SERVICE_LIST, JacksonUtils.transferToJsonNode(views));
result.put(FieldsConstants.COUNT, views.getTotalCount());
result.set(FieldsConstants.SERVICE_LIST, JacksonUtils.transferToJsonNode(views.getPageItems()));
return result;
}

View File

@ -1,5 +1,5 @@
#
# Copyright 1999-2018 Alibaba Group Holding Ltd.
# Copyright 1999-2025 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.
@ -13,8 +13,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
server.port=8848
server.servlet.context-path=/nacos
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.loadDataAtStart=true
com.alibaba.nacos.console.handler.impl.remote.ConsoleMaintainerClientAuthPlugin

View File

@ -1,253 +0,0 @@
#
# Copyright 1999-2024 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.
#
#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Include message field
server.error.include-message=ALWAYS
### Default web server port:
server.port=8848
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
# spring.datasource.platform=mysql
# nacos.plugin.datasource.log.enabled=true
#spring.sql.init.platform=mysql
### Count of DB:
# db.num=1
### 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=nacos
#db.password=nacos
### the maximum retry times for push
nacos.config.push.maxRetryTime=50
#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds:
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600
### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10
### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300
### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false
#*************** Metrics Related Configurations ***************#
### Metrics for prometheus
#management.endpoints.web.exposure.include=*
### Metrics for elastic search
management.elastic.metrics.export.enabled=false
#management.elastic.metrics.export.host=http://localhost:9200
### Metrics for influx
management.influx.metrics.export.enabled=false
#management.influx.metrics.export.db=springboot
#management.influx.metrics.export.influx.uri=http://localhost:8086
#management.influx.metrics.export.influx.auto-create-db=true
#management.influx.metrics.export.influx.consistency=one
#management.influx.metrics.export.influx.compressed=true
#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true
### accesslog automatic cleaning time
server.tomcat.accesslog.max-days=30
### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
### The directory of access log:
server.tomcat.basedir=file:.
#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth, is deprecated in 1.2.0:
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' and 'ldap' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system v3:
nacos.core.auth.enabled=false
nacos.core.auth.console.enabled=true
### 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
### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=false
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=
nacos.core.auth.server.identity.value=
### worked when nacos.core.auth.system.type=nacos
### The token expiration in seconds:
nacos.core.auth.plugin.nacos.token.cache.enable=false
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
### The default token (Base64 string):
#nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
nacos.core.auth.plugin.nacos.token.secret.key=
### 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.basedc=dc=example,dc=org
#nacos.core.auth.ldap.userDn=cn=admin,${nacos.core.auth.ldap.basedc}
#nacos.core.auth.ldap.password=admin
#nacos.core.auth.ldap.userdn=cn={0},dc=example,dc=org
#nacos.core.auth.ldap.filter.prefix=uid
#nacos.core.auth.ldap.case.sensitive=true
#nacos.core.auth.ldap.ignore.partial.result.exception=false
#*************** Control Plugin Related Configurations ***************#
# plugin type
#nacos.plugin.control.manager.type=nacos
# local control rule storage dir, default ${nacos.home}/data/connection and ${nacos.home}/data/tps
#nacos.plugin.control.rule.local.basedir=${nacos.home}
# external control rule storage type, if exist
#nacos.plugin.control.rule.external.storage=
#*************** Config Change Plugin Related Configurations ***************#
# webhook
#nacos.core.config.plugin.webhook.enabled=false
# It is recommended to use EB https://help.aliyun.com/document_detail/413974.html
#nacos.core.config.plugin.webhook.url=http://localhost:8080/webhook/send?token=***
# The content push max capacity ,byte
#nacos.core.config.plugin.webhook.contentMaxCapacity=102400
# whitelist
#nacos.core.config.plugin.whitelist.enabled=false
# The import file suffixs
#nacos.core.config.plugin.whitelist.suffixs=xml,text,properties,yaml,html
# fileformatcheck,which validate the import file of type and content
#nacos.core.config.plugin.fileformatcheck.enabled=false
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
###*************** Add from 1.3.0 ***************###
#*************** Core Related Configurations ***************#
### set the WorkerID manually
# nacos.core.snowflake.worker-id=
### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=
### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## 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 ***************#
### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
### enable to support prometheus service discovery
#nacos.prometheus.metrics.enabled=true
#************** Console UI Configuration ***************#
### Turn on/off the nacos console ui.
#nacos.console.ui.enabled=true
###*************** Add from 3.0.0 ***************###
#*************** Deployment Type Configuration ***************#
### Sets the deployment type: 'merged' for joint deployment, 'server' for separate deployment server only, 'console' for separate deployment console only.
nacos.deployment.type=merged
#************** Nacos Admin Compatibility Related Configurations ***************#
### Enabled for open API compatibility
# nacos.core.api.compatibility.client.enabled=true
### Enabled for admin API compatibility
# nacos.core.api.compatibility.admin.enabled=true
### Enabled for console API compatibility
# nacos.core.api.compatibility.console.enabled=false
#*************** K8s Related Configurations ***************#
### If turn on the K8s sync:
nacos.k8s.sync.enabled=false
### If use the Java API from an application outside a kubernetes cluster
#nacos.k8s.sync.outsideCluster=false
#nacos.k8s.sync.kubeConfig=/.kube/config
#*************** DistributedLock Configurations ***************#
# nacos.lock.default_expire_time = 30000000
# nacos.lock.max_expire_time = 1800000000

View File

@ -35,7 +35,7 @@
<link rel="stylesheet" type="text/css" href="console-ui/public/css/icon.css">
<link rel="stylesheet" type="text/css" href="console-ui/public/css/font-awesome.css">
<!-- 第三方css结束 -->
<link href="./css/main.css?e2df596fdcbaf967c31d" rel="stylesheet"></head>
<link href="./css/main.css?66b305f37e2c8be3d620" rel="stylesheet"></head>
<body>
<div id="root" style="overflow:hidden"></div>
@ -56,6 +56,6 @@
<script src="console-ui/public/js/merge.js"></script>
<script src="console-ui/public/js/loader.js"></script>
<!-- 第三方js结束 -->
<script type="text/javascript" src="./js/main.js?e2df596fdcbaf967c31d"></script></body>
<script type="text/javascript" src="./js/main.js?66b305f37e2c8be3d620"></script></body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -18,7 +18,7 @@ package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;
import com.alibaba.nacos.core.service.NamespaceOperationService;
import org.junit.jupiter.api.BeforeEach;

View File

@ -18,32 +18,29 @@ package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
import com.alibaba.nacos.core.service.NacosServerStateService;
import com.alibaba.nacos.sys.env.Constants;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateBuilder;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
/**
* ServerStateController unit test.
@ -58,50 +55,28 @@ class ServerStateControllerTest {
private static final String CONSOLE_URL = "/v1/console/server/state";
@Mock
private NacosServerStateService stateService;
@InjectMocks
private ServerStateController serverStateController;
private static List<ModuleStateBuilder> cachedBuilders;
private MockMvc mockmvc;
private ConfigurableEnvironment environment;
@BeforeAll
static void setUpBeforeAll() {
cachedBuilders = (List<ModuleStateBuilder>) ReflectionTestUtils.getField(ModuleStateHolder.getInstance(),
"moduleStateBuilders");
List<ModuleStateBuilder> mockBuilders = new LinkedList<>();
mockBuilders.add(new ModuleStateBuilder() {
@Override
public ModuleState build() {
ModuleState moduleState = new ModuleState("mock");
moduleState.newState(Constants.STARTUP_MODE_STATE, EnvUtil.STANDALONE_MODE_CLUSTER);
moduleState.newState(Constants.FUNCTION_MODE_STATE, null);
moduleState.newState(Constants.NACOS_VERSION, VersionUtils.version);
return moduleState;
}
@Override
public boolean isCacheable() {
return false;
}
});
ReflectionTestUtils.setField(ModuleStateHolder.getInstance(), "moduleStateBuilders", mockBuilders);
}
@BeforeEach
void setUp() {
environment = new MockEnvironment();
EnvUtil.setEnvironment(environment);
Map<String, String> mock = new HashMap<>();
mock.put(Constants.STARTUP_MODE_STATE, EnvUtil.STANDALONE_MODE_CLUSTER);
mock.put(Constants.FUNCTION_MODE_STATE, null);
mock.put(Constants.NACOS_VERSION, VersionUtils.version);
when(stateService.getServerState()).thenReturn(mock);
mockmvc = MockMvcBuilders.standaloneSetup(serverStateController).build();
}
@AfterAll
static void tearDownAfterAll() {
ReflectionTestUtils.setField(ModuleStateHolder.getInstance(), "moduleStateBuilders", cachedBuilders);
}
@Test
void serverState() throws Exception {
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(CONSOLE_URL);

View File

@ -19,7 +19,7 @@ package com.alibaba.nacos.console.controller.v2;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.NamespaceTypeEnum;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;

View File

@ -20,7 +20,7 @@ package com.alibaba.nacos.console.controller.v3.core;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.console.proxy.core.NamespaceProxy;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.console.controller.v3.naming;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.api.naming.pojo.Instance;
@ -25,7 +26,6 @@ import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.model.form.InstanceForm;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -45,8 +45,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* ConsoleInstanceControllerTest.
@ -74,9 +74,9 @@ public class ConsoleInstanceControllerTest {
@Test
void testGetInstanceList() throws Exception {
ObjectNode instances = JsonNodeFactory.instance.objectNode();
when(instanceProxy.listInstances(anyString(), anyString(), anyString(), anyString(), anyInt(),
anyInt())).thenReturn(instances);
Page<? extends Instance> page = new Page<>();
doReturn(page).when(instanceProxy)
.listInstances(anyString(), anyString(), anyString(), anyString(), anyInt(), anyInt());
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/v3/console/ns/instance/list")
.param("namespaceId", "default").param("serviceName", "testService").param("pageNo", "1")

View File

@ -21,6 +21,7 @@ import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceDetailInfo;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceView;
import com.alibaba.nacos.api.naming.pojo.maintainer.SubscriberInfo;
import com.alibaba.nacos.console.proxy.naming.ServiceProxy;
import com.alibaba.nacos.core.model.form.AggregationForm;
@ -146,9 +147,9 @@ public class ConsoleServiceControllerTest {
serviceForm.setNamespaceId("testNamespace");
serviceForm.setGroupName("testGroup");
Result<Object> actual = consoleServiceController.getServiceDetail(serviceForm);
verify(serviceProxy).getServiceDetail(any(String.class), any(String.class), any(String.class));
assertEquals(ErrorCode.SUCCESS.getCode(), actual.getCode());
// controller transfer ServiceDetailInfo to old console result
assertNotEquals(serviceDetail, actual.getData());
@ -202,8 +203,11 @@ public class ConsoleServiceControllerTest {
@Test
void testGetServiceList() throws Exception {
Page<ServiceView> expected = new Page<>();
expected.setTotalCount(1);
expected.getPageItems().add(new ServiceView());
when(serviceProxy.getServiceList(anyBoolean(), anyString(), anyInt(), anyInt(), anyString(), anyString(),
anyBoolean())).thenReturn(Collections.singletonList(new Object()));
anyBoolean())).thenReturn(expected);
PageForm pageForm = new PageForm();
pageForm.setPageNo(1);
pageForm.setPageSize(10);
@ -217,8 +221,8 @@ public class ConsoleServiceControllerTest {
anyBoolean());
assertEquals(ErrorCode.SUCCESS.getCode(), actual.getCode());
assertInstanceOf(List.class, actual.getData());
assertEquals(1, ((List<?>) actual.getData()).size());
assertInstanceOf(Page.class, actual.getData());
assertEquals(1, ((Page<?>) actual.getData()).getPageItems().size());
}
@Test

View File

@ -18,15 +18,12 @@ package com.alibaba.nacos.core.auth;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.auth.config.AuthErrorCode;
import com.alibaba.nacos.auth.config.AuthModuleStateBuilder;
import com.alibaba.nacos.auth.config.NacosAuthConfig;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.config.AbstractDynamicConfig;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import com.alibaba.nacos.sys.utils.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -156,11 +153,6 @@ public class NacosServerAuthConfig extends AbstractDynamicConfig implements Naco
serverIdentityKey = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_KEY, "");
serverIdentityValue = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_VALUE, "");
refreshPluginProperties();
ModuleStateHolder.getInstance().getModuleState(AuthModuleStateBuilder.AUTH_MODULE)
.ifPresent(moduleState -> {
ModuleState temp = new AuthModuleStateBuilder().build();
moduleState.getStates().putAll(temp.getStates());
});
} catch (Exception e) {
LOGGER.warn("Upgrade auth config from env failed, use old value", e);
}

View File

@ -19,11 +19,11 @@ package com.alibaba.nacos.core.controller.v3;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;
import com.alibaba.nacos.core.service.NamespaceOperationService;
@ -53,7 +53,7 @@ import static com.alibaba.nacos.core.utils.Commons.NACOS_ADMIN_CORE_CONTEXT_V3;
*/
@NacosApi
@RestController
@RequestMapping(NACOS_ADMIN_CORE_CONTEXT_V3 + "namespace")
@RequestMapping(NACOS_ADMIN_CORE_CONTEXT_V3 + "/namespace")
public class NamespaceControllerV3 {
private final NamespaceOperationService namespaceOperationService;
@ -116,6 +116,7 @@ public class NamespaceControllerV3 {
if (StringUtils.isBlank(namespaceId)) {
namespaceId = UUID.randomUUID().toString();
} else {
// TODO check should be parameter check filter.
namespaceId = namespaceId.trim();
if (!namespaceIdCheckPattern.matcher(namespaceId).matches()) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_NAMESPACE,
@ -125,11 +126,6 @@ public class NamespaceControllerV3 {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_NAMESPACE,
"too long namespaceId, over " + NAMESPACE_ID_MAX_LENGTH);
}
// check unique
if (namespacePersistService.tenantInfoCountByTenantId(namespaceId) > 0) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_NAMESPACE,
"the namespaceId is existed, namespaceId: " + namespaceForm.getNamespaceId());
}
}
// contains illegal chars
if (!namespaceNameCheckPattern.matcher(namespaceName).matches()) {

View File

@ -0,0 +1,84 @@
/*
* Copyright 1999-2025 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.core.controller.v3;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.core.cluster.health.ModuleHealthCheckerHolder;
import com.alibaba.nacos.core.cluster.health.ReadinessResult;
import com.alibaba.nacos.core.service.NacosServerStateService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import static com.alibaba.nacos.core.utils.Commons.NACOS_ADMIN_CORE_CONTEXT_V3;
/**
* Server state controller for admin API.
*
* @author xiweng.yy
*/
@NacosApi
@RestController
@RequestMapping(NACOS_ADMIN_CORE_CONTEXT_V3 + "/state")
public class ServerStateController {
private final NacosServerStateService stateService;
public ServerStateController(NacosServerStateService stateService) {
this.stateService = stateService;
}
/**
* Get server state of current server.
*
* @return state key-value map.
*/
@GetMapping()
public Result<Map<String, String>> serverState() {
return Result.success(stateService.getServerState());
}
/**
* Whether the Nacos is in broken states or not, and cannot recover except by being restarted.
*
* @return HTTP code equal to 200 indicates that Nacos is in right states. HTTP code equal to 500 indicates that
* Nacos is in broken states.
*/
@GetMapping("/liveness")
public Result<String> liveness() {
return Result.success("ok");
}
/**
* Ready to receive the request or not.
*
* @return HTTP code equal to 200 indicates that Nacos is ready. HTTP code equal to 500 indicates that Nacos is not
* ready.
*/
@GetMapping("/readiness")
public Result<String> readiness() throws NacosException {
ReadinessResult result = ModuleHealthCheckerHolder.getInstance().checkReadiness();
if (result.isSuccess()) {
return Result.success("ok");
}
return Result.failure(result.getResultMessage());
}
}

View File

@ -16,7 +16,7 @@
package com.alibaba.nacos.core.namespace.injector;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
/**
* Namespace detail injector.

View File

@ -16,7 +16,7 @@
package com.alibaba.nacos.core.namespace.injector;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import java.util.HashSet;
import java.util.Set;

View File

@ -1,115 +0,0 @@
/*
* Copyright 1999-2023 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.core.namespace.model;
/**
* Namespace.
*
* @author diamond
*/
public class Namespace {
private String namespace;
private String namespaceShowName;
private String namespaceDesc;
private int quota;
private int configCount;
/**
* see {@link NamespaceTypeEnum}.
*/
private int type;
public String getNamespaceShowName() {
return namespaceShowName;
}
public void setNamespaceShowName(String namespaceShowName) {
this.namespaceShowName = namespaceShowName;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public Namespace() {
}
public Namespace(String namespace, String namespaceShowName) {
this.namespace = namespace;
this.namespaceShowName = namespaceShowName;
}
public Namespace(String namespace, String namespaceShowName, int quota, int configCount, int type) {
this.namespace = namespace;
this.namespaceShowName = namespaceShowName;
this.quota = quota;
this.configCount = configCount;
this.type = type;
}
public Namespace(String namespace, String namespaceShowName, String namespaceDesc, int quota, int configCount,
int type) {
this.namespace = namespace;
this.namespaceShowName = namespaceShowName;
this.quota = quota;
this.configCount = configCount;
this.type = type;
this.namespaceDesc = namespaceDesc;
}
public String getNamespaceDesc() {
return namespaceDesc;
}
public void setNamespaceDesc(String namespaceDesc) {
this.namespaceDesc = namespaceDesc;
}
public int getQuota() {
return quota;
}
public void setQuota(int quota) {
this.quota = quota;
}
public int getConfigCount() {
return configCount;
}
public void setConfigCount(int configCount) {
this.configCount = configCount;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}

View File

@ -21,7 +21,7 @@ import java.io.Serializable;
/**
* TenantInfo.
*
* <p>Old name of {@link Namespace}</p>
* <p>Old name of {@link com.alibaba.nacos.api.model.response.Namespace}</p>
*
* @author Nacos
*/

View File

@ -0,0 +1,46 @@
/*
* Copyright 1999-2025 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.core.service;
import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* Nacos server state service.
*
* @author xiweng.yy
*/
@Service
public class NacosServerStateService {
/**
* Get current server states.
*
* @return server states key-value map.
*/
public Map<String, String> getServerState() {
Map<String, String> serverState = new HashMap<>(4);
for (ModuleState each : ModuleStateHolder.getInstance().getAllModuleStates()) {
each.getStates().forEach((s, o) -> serverState.put(s, null == o ? null : o.toString()));
}
return serverState;
}
}

View File

@ -18,11 +18,11 @@ package com.alibaba.nacos.core.service;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.namespace.injector.NamespaceDetailInjectorHolder;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.core.namespace.model.NamespaceTypeEnum;
import com.alibaba.nacos.core.namespace.model.TenantInfo;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;

View File

@ -18,9 +18,9 @@ package com.alibaba.nacos.core.controller.v3;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.core.namespace.model.form.NamespaceForm;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;
import com.alibaba.nacos.core.service.NamespaceOperationService;
@ -102,19 +102,16 @@ class NamespaceControllerV3Test {
form.setNamespaceName(TEST_NAMESPACE_NAME);
form.setNamespaceDesc(TEST_NAMESPACE_DESC);
when(namespaceOperationService.createNamespace(
TEST_NAMESPACE_ID,
TEST_NAMESPACE_NAME,
TEST_NAMESPACE_DESC
)).thenReturn(true);
when(namespaceOperationService.createNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME,
TEST_NAMESPACE_DESC)).thenReturn(true);
Result<Boolean> result = namespaceControllerV3.createNamespace(form);
Assertions.assertNotNull(result);
Assertions.assertEquals(ErrorCode.SUCCESS.getCode(), (int) result.getCode());
Assertions.assertTrue(result.getData());
verify(namespaceOperationService, times(1))
.createNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME, TEST_NAMESPACE_DESC);
verify(namespaceOperationService, times(1)).createNamespace(TEST_NAMESPACE_ID, TEST_NAMESPACE_NAME,
TEST_NAMESPACE_DESC);
}
@Test
@ -138,19 +135,15 @@ class NamespaceControllerV3Test {
form.setNamespaceName("updated-name");
form.setNamespaceDesc("updated-desc");
when(namespaceOperationService.editNamespace(
TEST_NAMESPACE_ID,
"updated-name",
"updated-desc"
)).thenReturn(true);
when(namespaceOperationService.editNamespace(TEST_NAMESPACE_ID, "updated-name", "updated-desc")).thenReturn(
true);
Result<Boolean> result = namespaceControllerV3.updateNamespace(form);
Assertions.assertNotNull(result);
Assertions.assertEquals(ErrorCode.SUCCESS.getCode(), (int) result.getCode());
Assertions.assertTrue(result.getData());
verify(namespaceOperationService, times(1))
.editNamespace(TEST_NAMESPACE_ID, "updated-name", "updated-desc");
verify(namespaceOperationService, times(1)).editNamespace(TEST_NAMESPACE_ID, "updated-name", "updated-desc");
}
@Test

View File

@ -21,7 +21,7 @@ import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.core.namespace.injector.AbstractNamespaceDetailInjector;
import com.alibaba.nacos.core.namespace.model.Namespace;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.core.namespace.model.NamespaceTypeEnum;
import com.alibaba.nacos.core.namespace.model.TenantInfo;
import com.alibaba.nacos.core.namespace.repository.NamespacePersistService;

View File

@ -190,6 +190,9 @@ nacos.console.port=8080
### Nacos Server Web context path:
nacos.console.contextPath=
### Nacos Server context path, which link to nacos server `nacos.server.contextPath`, works when deployment type is `console`
nacos.console.remote.server.context-path=/nacos
#************** Console UI Configuration ***************#
### Turn on/off the nacos console ui.

View File

@ -71,6 +71,8 @@ public class Constants {
public static final String CORE_OPS_ADMIN_PATH = "/v3/admin/core/ops";
public static final String CORE_NAMESPACE_ADMIN_PATH = "/v3/admin/core/namespace";
public static final String CORE_STATE_ADMIN_PATH = "/v3/admin/core/state";
}
}

View File

@ -52,6 +52,33 @@ public abstract class AbstractCoreMaintainerService implements CoreMaintainerSer
ParamUtil.initSerialization();
}
@Override
public Map<String, String> getServerState() throws NacosException {
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.GET)
.setPath(Constants.AdminApiPath.CORE_STATE_ADMIN_PATH).build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
Result<Map<String, String>> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Map<String, String>>>() {
});
return result.getData();
}
@Override
public Boolean liveness() throws NacosException {
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.GET)
.setPath(Constants.AdminApiPath.CORE_STATE_ADMIN_PATH + "/liveness").build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
return httpRestResult.ok();
}
@Override
public Boolean readiness() throws NacosException {
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.GET)
.setPath(Constants.AdminApiPath.CORE_OPS_ADMIN_PATH + "/readiness").build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
return httpRestResult.ok();
}
@Override
public String raftOps(String command, String value, String groupId) throws NacosException {
Map<String, String> params = new HashMap<>(8);
@ -201,9 +228,8 @@ public abstract class AbstractCoreMaintainerService implements CoreMaintainerSer
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.GET)
.setPath(Constants.AdminApiPath.CORE_NAMESPACE_ADMIN_PATH).setParamValue(params).build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
Result<Namespace> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Namespace>>() {
});
Result<Namespace> result = JacksonUtils.toObj(httpRestResult.getData(), new TypeReference<Result<Namespace>>() {
});
return result.getData();
}
@ -218,9 +244,8 @@ public abstract class AbstractCoreMaintainerService implements CoreMaintainerSer
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.POST)
.setPath(Constants.AdminApiPath.CORE_NAMESPACE_ADMIN_PATH).setParamValue(params).build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
Result<Boolean> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Boolean>>() {
});
Result<Boolean> result = JacksonUtils.toObj(httpRestResult.getData(), new TypeReference<Result<Boolean>>() {
});
return result.getData();
}
@ -235,9 +260,8 @@ public abstract class AbstractCoreMaintainerService implements CoreMaintainerSer
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.PUT)
.setPath(Constants.AdminApiPath.CORE_NAMESPACE_ADMIN_PATH).setParamValue(params).build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
Result<Boolean> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Boolean>>() {
});
Result<Boolean> result = JacksonUtils.toObj(httpRestResult.getData(), new TypeReference<Result<Boolean>>() {
});
return result.getData();
}
@ -249,9 +273,8 @@ public abstract class AbstractCoreMaintainerService implements CoreMaintainerSer
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.DELETE)
.setPath(Constants.AdminApiPath.CORE_NAMESPACE_ADMIN_PATH).setParamValue(params).build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
Result<Boolean> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Boolean>>() {
});
Result<Boolean> result = JacksonUtils.toObj(httpRestResult.getData(), new TypeReference<Result<Boolean>>() {
});
return result.getData();
}
@ -263,9 +286,8 @@ public abstract class AbstractCoreMaintainerService implements CoreMaintainerSer
HttpRequest httpRequest = new HttpRequest.Builder().setHttpMethod(HttpMethod.GET)
.setPath(Constants.AdminApiPath.CORE_NAMESPACE_ADMIN_PATH + "/check").setParamValue(params).build();
HttpRestResult<String> httpRestResult = clientHttpProxy.executeSyncHttpRequest(httpRequest);
Result<Integer> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Integer>>() {
});
Result<Integer> result = JacksonUtils.toObj(httpRestResult.getData(), new TypeReference<Result<Integer>>() {
});
return result.getData() > 0;
}

View File

@ -22,6 +22,7 @@ import com.alibaba.nacos.api.model.response.IdGeneratorInfo;
import com.alibaba.nacos.api.model.response.NacosMember;
import com.alibaba.nacos.api.model.response.Namespace;
import com.alibaba.nacos.api.model.response.ServerLoaderMetrics;
import com.alibaba.nacos.common.utils.StringUtils;
import java.util.Collection;
import java.util.List;
@ -34,6 +35,30 @@ import java.util.Map;
*/
public interface CoreMaintainerService {
/**
* Get Nacos server states.
*
* @return the states key-value map
* @throws NacosException if the operation fails.
*/
Map<String, String> getServerState() throws NacosException;
/**
* Detect server liveness.
*
* @return {@code true} detect successfully, {@code false} otherwise.
* @throws NacosException if the operation fails.
*/
Boolean liveness() throws NacosException;
/**
* Detect server readiness.
*
* @return {@code true} detect successfully, {@code false} otherwise.
* @throws NacosException if the operation fails.
*/
Boolean readiness() throws NacosException;
/**
* Execute a Raft operation with the specified command, value, and group ID.
*
@ -143,10 +168,22 @@ public interface CoreMaintainerService {
*/
Namespace getNamespace(String namespaceId) throws NacosException;
/**
* Create a new namespace with the provided details and auto-generate UUID.
*
* @param namespaceName The name of the new namespace.
* @param namespaceDesc The description of the new namespace.
* @return {@code true} if the namespace is created successfully, {@code false} otherwise.
* @throws NacosException Thrown if any error occurs during the creation.
*/
default Boolean createNamespace(String namespaceName, String namespaceDesc) throws NacosException {
return createNamespace(StringUtils.EMPTY, namespaceName, namespaceDesc);
}
/**
* Create a new namespace with the provided details.
*
* @param namespaceId The unique identifier for the new namespace.
* @param namespaceId The unique identifier for the new namespace, if null or empty will use auto-generate UUID.
* @param namespaceName The name of the new namespace.
* @param namespaceDesc The description of the new namespace.
* @return {@code true} if the namespace is created successfully, {@code false} otherwise.
@ -159,7 +196,7 @@ public interface CoreMaintainerService {
*
* @param namespaceId The unique identifier of the namespace to be updated.
* @param namespaceName The new name for the namespace (can be null).
* @param namespaceDesc The new description for the namespace (can be null).
* @param namespaceDesc The new description for the namespace.
* @return {@code true} if the namespace is updated successfully, {@code false} otherwise.
* @throws NacosException Thrown if any error occurs during the update.
*/

View File

@ -117,23 +117,23 @@ public class NacosNamingMaintainerServiceImpl extends AbstractCoreMaintainerServ
}
@Override
public List<ServiceView> listServices(String namespaceId, String groupNameParam, String serviceNameParam,
public Page<ServiceView> listServices(String namespaceId, String groupNameParam, String serviceNameParam,
boolean ignoreEmptyService, int pageNo, int pageSize) throws NacosException {
HttpRestResult<String> httpRestResult = doListServices(namespaceId, groupNameParam, serviceNameParam, false,
ignoreEmptyService, pageNo, pageSize);
Result<List<ServiceView>> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<List<ServiceView>>>() {
Result<Page<ServiceView>> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Page<ServiceView>>>() {
});
return result.getData();
}
@Override
public List<ServiceDetailInfo> listServicesWithDetail(String namespaceId, String groupNameParam,
public Page<ServiceDetailInfo> listServicesWithDetail(String namespaceId, String groupNameParam,
String serviceNameParam, int pageNo, int pageSize) throws NacosException {
HttpRestResult<String> httpRestResult = doListServices(namespaceId, groupNameParam, serviceNameParam, true,
false, pageNo, pageSize);
Result<List<ServiceDetailInfo>> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<List<ServiceDetailInfo>>>() {
Result<Page<ServiceDetailInfo>> result = JacksonUtils.toObj(httpRestResult.getData(),
new TypeReference<Result<Page<ServiceDetailInfo>>>() {
});
return result.getData();
}

View File

@ -330,10 +330,10 @@ public interface ServiceMaintainerService {
* <p>Only list the first 100 services if this namespace contains more than 100 services</p>
*
* @param namespaceId target namespace id
* @return list of service view, {@link ServiceView} is a summary of service.
* @return page of service view, {@link ServiceView} is a summary of service.
* @throws NacosException if an error occurs
*/
default List<ServiceView> listServices(String namespaceId) throws NacosException {
default Page<ServiceView> listServices(String namespaceId) throws NacosException {
return listServices(namespaceId, StringUtils.EMPTY, StringUtils.EMPTY);
}
@ -345,10 +345,10 @@ public interface ServiceMaintainerService {
* @param namespaceId target namespace id
* @param groupNameParam the group name pattern, e.g., "" for all groups, "group" for all services groupName match `.*group.*`.
* @param serviceNameParam the service name pattern, e.g., "" for all services, "service" for all services name match `.*service.*`.
* @return list of service view, {@link ServiceView} is a summary of service.
* @return page of service view, {@link ServiceView} is a summary of service.
* @throws NacosException if an error occurs
*/
default List<ServiceView> listServices(String namespaceId, String groupNameParam, String serviceNameParam)
default Page<ServiceView> listServices(String namespaceId, String groupNameParam, String serviceNameParam)
throws NacosException {
return listServices(namespaceId, groupNameParam, serviceNameParam, true, 1, 100);
}
@ -364,10 +364,10 @@ public interface ServiceMaintainerService {
* @param ignoreEmptyService whether ignore empty service, {@code true} will exclude these services without any instance.
* @param pageNo page number, start from 1
* @param pageSize page size per page
* @return list of service view, {@link ServiceView} is a summary of service.
* @return page of service view, {@link ServiceView} is a summary of service.
* @throws NacosException if an error occurs
*/
List<ServiceView> listServices(String namespaceId, String groupNameParam, String serviceNameParam,
Page<ServiceView> listServices(String namespaceId, String groupNameParam, String serviceNameParam,
boolean ignoreEmptyService, int pageNo, int pageSize) throws NacosException;
/**
@ -381,10 +381,10 @@ public interface ServiceMaintainerService {
* </p>
*
* @param namespaceId target namespace id
* @return list of service detail, {@link ServiceDetailInfo} is a detail info of service.
* @return page of service detail, {@link ServiceDetailInfo} is a detail info of service.
* @throws NacosException if an error occurs
*/
default List<ServiceDetailInfo> listServicesWithDetail(String namespaceId) throws NacosException {
default Page<ServiceDetailInfo> listServicesWithDetail(String namespaceId) throws NacosException {
return listServicesWithDetail(namespaceId, StringUtils.EMPTY, StringUtils.EMPTY);
}
@ -401,10 +401,10 @@ public interface ServiceMaintainerService {
* @param namespaceId target namespace id
* @param groupNameParam the group name pattern, e.g., "" for all groups, "group" for all services groupName match `.*group.*`.
* @param serviceNameParam the service name pattern, e.g., "" for all services, "service" for all services name match `.*service.*`.
* @return list of service detail, {@link ServiceDetailInfo} is a detail info of service.
* @return page of service detail, {@link ServiceDetailInfo} is a detail info of service.
* @throws NacosException if an error occurs
*/
default List<ServiceDetailInfo> listServicesWithDetail(String namespaceId, String groupNameParam,
default Page<ServiceDetailInfo> listServicesWithDetail(String namespaceId, String groupNameParam,
String serviceNameParam) throws NacosException {
return listServicesWithDetail(namespaceId, groupNameParam, serviceNameParam, 1, 100);
}
@ -423,10 +423,10 @@ public interface ServiceMaintainerService {
* @param serviceNameParam the service name pattern, e.g., "" for all services, "service" for all services name match `.*service.*`.
* @param pageNo page number, start from 1
* @param pageSize page size per page
* @return list of service detail, {@link ServiceDetailInfo} is a detail info of service.
* @return page of service detail, {@link ServiceDetailInfo} is a detail info of service.
* @throws NacosException if an error occurs
*/
List<ServiceDetailInfo> listServicesWithDetail(String namespaceId, String groupNameParam, String serviceNameParam,
Page<ServiceDetailInfo> listServicesWithDetail(String namespaceId, String groupNameParam, String serviceNameParam,
int pageNo, int pageSize) throws NacosException;
/**

View File

@ -43,7 +43,6 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ScheduledExecutorService;
@ -206,13 +205,8 @@ public class ClientHttpProxy {
clientAuthPluginManager.getAuthServiceSpiImplSet().forEach(clientAuthService -> {
LoginIdentityContext loginIdentityContext = clientAuthService.getLoginIdentityContext(
new RequestResource());
if (loginIdentityContext != null) {
if (loginIdentityContext.getAllKey().contains(NacosAuthLoginConstant.ACCESSTOKEN)) {
Map<String, String> accessToken = new HashMap<>(4);
accessToken.put(NacosAuthLoginConstant.ACCESSTOKEN,
loginIdentityContext.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
header.addAll(accessToken);
}
for (String key : loginIdentityContext.getAllKey()) {
header.addParam(key, loginIdentityContext.getParameter(key));
}
});
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.maintainer.client.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.response.ConnectionInfo;
import com.alibaba.nacos.api.model.response.IdGeneratorInfo;
import com.alibaba.nacos.api.model.response.NacosMember;
@ -24,6 +25,7 @@ import com.alibaba.nacos.api.model.response.ServerLoaderMetrics;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.maintainer.client.remote.ClientHttpProxy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -299,7 +301,6 @@ class AbstractCoreMaintainerServiceTest {
@Test
void testCreateNamespace() throws Exception {
// Arrange
String namespaceId = "test-namespace-id";
String namespaceName = "test-namespace-name";
String namespaceDesc = "test-namespace-desc";
HttpRestResult<String> mockHttpRestResult = new HttpRestResult<>();
@ -308,7 +309,7 @@ class AbstractCoreMaintainerServiceTest {
when(clientHttpProxy.executeSyncHttpRequest(any())).thenReturn(mockHttpRestResult);
// Act
Boolean result = coreMaintainerService.createNamespace(namespaceId, namespaceName, namespaceDesc);
Boolean result = coreMaintainerService.createNamespace(namespaceName, namespaceDesc);
// Assert
assertTrue(result);
@ -384,4 +385,46 @@ class AbstractCoreMaintainerServiceTest {
assertFalse(result);
verify(clientHttpProxy, times(1)).executeSyncHttpRequest(any());
}
@Test
void getServerState() throws JsonProcessingException, NacosException {
Map<String, String> serverState = new HashMap<>();
serverState.put("key", "value");
HttpRestResult<String> mockHttpRestResult = new HttpRestResult<>();
mockHttpRestResult.setData(new ObjectMapper().writeValueAsString(new Result<>(serverState))); // 0表示不存在
when(clientHttpProxy.executeSyncHttpRequest(any())).thenReturn(mockHttpRestResult);
Map<String, String> result = coreMaintainerService.getServerState();
assertEquals(1, result.size());
assertEquals("value", result.get("key"));
}
@Test
void liveness() throws NacosException {
HttpRestResult<String> mockHttpRestResult = new HttpRestResult<>();
mockHttpRestResult.setCode(200);
when(clientHttpProxy.executeSyncHttpRequest(any())).thenReturn(mockHttpRestResult);
Boolean result = coreMaintainerService.liveness();
assertTrue(result);
mockHttpRestResult.setCode(500);
result = coreMaintainerService.liveness();
assertFalse(result);
}
@Test
void readiness() throws NacosException {
HttpRestResult<String> mockHttpRestResult = new HttpRestResult<>();
mockHttpRestResult.setCode(200);
when(clientHttpProxy.executeSyncHttpRequest(any())).thenReturn(mockHttpRestResult);
Boolean result = coreMaintainerService.readiness();
assertTrue(result);
mockHttpRestResult.setCode(500);
result = coreMaintainerService.readiness();
assertFalse(result);
}
}

View File

@ -157,53 +157,55 @@ public class NacosNamingMaintainerServiceImplTest {
@Test
void testListServices() throws Exception {
List<ServiceView> expected = new ArrayList<>();
expected.add(new ServiceView());
expected.get(0).setName("testService");
expected.get(0).setGroupName("testGroup");
Page<ServiceView> expected = new Page<>();
expected.getPageItems().add(new ServiceView());
expected.getPageItems().get(0).setName("testService");
expected.getPageItems().get(0).setGroupName("testGroup");
HttpRestResult<String> mockHttpRestResult = new HttpRestResult<>();
mockHttpRestResult.setData(new ObjectMapper().writeValueAsString(new Result<>(expected)));
when(clientHttpProxy.executeSyncHttpRequest(any())).thenReturn(mockHttpRestResult);
// Act
List<ServiceView> result = nacosNamingMaintainerService.listServices("testNamespace");
Page<ServiceView> result = nacosNamingMaintainerService.listServices("testNamespace");
// Assert
assertNotNull(result);
assertEquals(1, result.size());
assertEquals("testService", result.get(0).getName());
assertEquals("testGroup", result.get(0).getGroupName());
assertEquals(1, result.getPageItems().size());
assertEquals("testService", result.getPageItems().get(0).getName());
assertEquals("testGroup", result.getPageItems().get(0).getGroupName());
verify(clientHttpProxy, times(1)).executeSyncHttpRequest(any());
}
@Test
void testListServicesWithDetail() throws Exception {
// Arrange
String namespaceId = "testNamespace";
List<ServiceDetailInfo> expected = new ArrayList<>();
expected.add(new ServiceDetailInfo());
expected.get(0).setNamespaceId(namespaceId);
expected.get(0).setServiceName("testService");
expected.get(0).setGroupName("testGroup");
expected.get(0).setMetadata(Collections.singletonMap("key", "value"));
expected.get(0).setClusterMap(Collections.emptyMap());
Page<ServiceDetailInfo> expected = new Page<>();
List<ServiceDetailInfo> expectedItem = new ArrayList<>();
expected.setPageItems(expectedItem);
expected.setTotalCount(1);
expectedItem.add(new ServiceDetailInfo());
expectedItem.get(0).setNamespaceId("testNamespace");
expectedItem.get(0).setServiceName("testService");
expectedItem.get(0).setGroupName("testGroup");
expectedItem.get(0).setMetadata(Collections.singletonMap("key", "value"));
expectedItem.get(0).setClusterMap(Collections.emptyMap());
HttpRestResult<String> mockHttpRestResult = new HttpRestResult<>();
mockHttpRestResult.setData(new ObjectMapper().writeValueAsString(new Result<>(expected)));
when(clientHttpProxy.executeSyncHttpRequest(any())).thenReturn(mockHttpRestResult);
// Act
List<ServiceDetailInfo> result = nacosNamingMaintainerService.listServicesWithDetail(namespaceId);
Page<ServiceDetailInfo> result = nacosNamingMaintainerService.listServicesWithDetail("testNamespace");
// Assert
assertNotNull(result);
assertEquals(1, result.size());
assertEquals(namespaceId, result.get(0).getNamespaceId());
assertEquals("testService", result.get(0).getServiceName());
assertEquals("testGroup", result.get(0).getGroupName());
assertEquals(Collections.singletonMap("key", "value"), result.get(0).getMetadata());
assertEquals(Collections.emptyMap(), result.get(0).getClusterMap());
assertEquals(1, result.getPageItems().size());
assertEquals("testNamespace", result.getPageItems().get(0).getNamespaceId());
assertEquals("testService", result.getPageItems().get(0).getServiceName());
assertEquals("testGroup", result.getPageItems().get(0).getGroupName());
assertEquals(Collections.singletonMap("key", "value"), result.getPageItems().get(0).getMetadata());
assertEquals(Collections.emptyMap(), result.getPageItems().get(0).getClusterMap());
verify(clientHttpProxy, times(1)).executeSyncHttpRequest(any());
}

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceDetailInfo;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
@ -40,6 +41,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedList;
import java.util.List;
/**
@ -143,9 +145,13 @@ public class CatalogController {
@RequestParam(required = false) boolean hasIpCount) throws NacosException {
if (withInstances) {
ServiceDetailInfo serviceDetailInfo = (ServiceDetailInfo) judgeCatalogService().pageListServiceDetail(
Page<ServiceDetailInfo> serviceDetailInfo = judgeCatalogService().pageListServiceDetail(
namespaceId, groupName, serviceName, pageNo, pageSize);
return com.alibaba.nacos.naming.pojo.ServiceDetailInfo.from(serviceDetailInfo);
List<com.alibaba.nacos.naming.pojo.ServiceDetailInfo> result = new LinkedList<>();
for (ServiceDetailInfo each : serviceDetailInfo.getPageItems()) {
result.add(com.alibaba.nacos.naming.pojo.ServiceDetailInfo.from(each));
}
return result;
}
return judgeCatalogService().pageListService(namespaceId, groupName, serviceName, pageNo, pageSize,
containedInstance, hasIpCount);

View File

@ -147,7 +147,7 @@ public class ServiceControllerV3 {
*
* <ul>
* <li>
* if {@link ServiceListForm#isWithInstances()} is {@code true}, will return list {@link ServiceDetailInfo }
* if {@link ServiceListForm#isWithInstances()} is {@code true}, will return page {@link ServiceDetailInfo }
* </li>
* <li>
* if {@link ServiceListForm#isWithInstances()} is {@code false}, will return list {@link ServiceView }

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.naming.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceDetailInfo;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceView;
@ -48,7 +49,7 @@ public interface CatalogService {
* @param groupName group name of service
* @param serviceName service name
* @param clusterName cluster name of instances
* @return instances list
* @return instances page object
* @throws NacosException exception in query
*/
List<? extends Instance> listInstances(String namespaceId, String groupName, String serviceName, String clusterName)
@ -90,11 +91,11 @@ public interface CatalogService {
* @param serviceName service name
* @param pageNo page number
* @param pageSize page size
* @return service list
* @return service page object
* @throws NacosException exception in query
*/
Object pageListServiceDetail(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize)
throws NacosException;
Page<ServiceDetailInfo> pageListServiceDetail(String namespaceId, String groupName, String serviceName, int pageNo,
int pageSize) throws NacosException;
/**
* List service by page.
@ -105,10 +106,10 @@ public interface CatalogService {
* @param pageNo page number
* @param pageSize page size
* @param ignoreEmptyService whether ignore empty service
* @return service list
* @return service page object
* @throws NacosException exception in query
*/
List<ServiceView> listService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize,
Page<ServiceView> listService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize,
boolean ignoreEmptyService) throws NacosException;
}

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.naming.core;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.pojo.maintainer.ClusterInfo;
@ -37,7 +38,6 @@ import com.alibaba.nacos.naming.utils.ServiceUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -161,15 +161,17 @@ public class CatalogServiceV2Impl implements CatalogService {
}
@Override
public List<ServiceView> listService(String namespaceId, String groupName, String serviceName, int pageNo,
public Page<ServiceView> listService(String namespaceId, String groupName, String serviceName, int pageNo,
int pageSize, boolean ignoreEmptyService) throws NacosException {
List<ServiceView> serviceViews = new LinkedList<>();
Page<ServiceView> serviceViews = new Page<>();
Collection<Service> services = patternServices(namespaceId, groupName, serviceName);
if (ignoreEmptyService) {
services = services.stream().filter(each -> 0 != serviceStorage.getData(each).ipCount())
.collect(Collectors.toList());
services = services.stream().filter(each -> 0 != serviceStorage.getData(each).ipCount()).toList();
}
services = PageUtil.subPageList(services.stream().toList(), pageNo, pageSize);
Page<Service> page = PageUtil.subPage(services.stream().toList(), pageNo, pageSize);
serviceViews.setTotalCount(page.getTotalCount());
serviceViews.setPageNumber(page.getPageNumber());
serviceViews.setPagesAvailable(page.getPagesAvailable());
for (Service each : services) {
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(each).orElseGet(ServiceMetadata::new);
ServiceView serviceView = new ServiceView();
@ -179,7 +181,7 @@ public class CatalogServiceV2Impl implements CatalogService {
serviceView.setIpCount(serviceStorage.getData(each).ipCount());
serviceView.setHealthyInstanceCount(countHealthyInstance(serviceStorage.getData(each)));
serviceView.setTriggerFlag(isProtectThreshold(serviceView, serviceMetadata) ? "true" : "false");
serviceViews.add(serviceView);
serviceViews.getPageItems().add(serviceView);
}
return serviceViews;
}
@ -200,20 +202,25 @@ public class CatalogServiceV2Impl implements CatalogService {
}
@Override
public Object pageListServiceDetail(String namespaceId, String groupName, String serviceName, int pageNo,
int pageSize) throws NacosException {
List<ServiceDetailInfo> result = new ArrayList<>();
public Page<ServiceDetailInfo> pageListServiceDetail(String namespaceId, String groupName, String serviceName,
int pageNo, int pageSize) throws NacosException {
Collection<Service> services = patternServices(namespaceId, groupName, serviceName);
services = doPage(services, pageNo - 1, pageSize);
for (Service each : services) {
Page<Service> servicePage = PageUtil.subPage(services.stream().toList(), pageNo, pageSize);
Page<ServiceDetailInfo> result = new Page<>();
result.setPagesAvailable(servicePage.getPagesAvailable());
result.setPageNumber(servicePage.getPageNumber());
result.setTotalCount(servicePage.getTotalCount());
List<ServiceDetailInfo> pagedItem = new LinkedList<>();
for (Service each : servicePage.getPageItems()) {
ServiceDetailInfo serviceDetailInfo = new ServiceDetailInfo();
serviceDetailInfo.setServiceName(each.getName());
serviceDetailInfo.setGroupName(each.getGroup());
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(each).orElseGet(ServiceMetadata::new);
serviceDetailInfo.setMetadata(serviceMetadata.getExtendData());
serviceDetailInfo.setClusterMap(getClusterMap(each));
result.add(serviceDetailInfo);
pagedItem.add(serviceDetailInfo);
}
result.setPageItems(pagedItem);
return result;
}

View File

@ -1,36 +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.
#
server.port=8848
server.servlet.context-path=/nacos
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.max-active=15
## Validate the connection before borrowing it from the pool.
#spring.datasource.test-on-borrow=true
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200
# metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
# default current work dir
server.tomcat.basedir=file:.

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.naming.controllers;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceDetailInfo;
import com.alibaba.nacos.naming.core.CatalogServiceV2Impl;
@ -30,7 +31,6 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -93,7 +93,7 @@ class CatalogControllerTest {
void testListDetail() {
try {
when(catalogServiceV2.pageListServiceDetail(Constants.DEFAULT_NAMESPACE_ID, TEST_GROUP_NAME,
TEST_SERVICE_NAME, 1, 10)).thenReturn(Collections.emptyList());
TEST_SERVICE_NAME, 1, 10)).thenReturn(new Page<>());
Object res = catalogController.listDetail(true, Constants.DEFAULT_NAMESPACE_ID, 1, 10, TEST_SERVICE_NAME,
TEST_GROUP_NAME, null, true);
assertTrue(res instanceof List);

View File

@ -156,8 +156,8 @@ class ServiceControllerV3Test {
@Test
void testList() throws Exception {
List<ServiceView> result = new LinkedList<>();
result.add(new ServiceView());
Page<ServiceView> result = new Page<>();
result.getPageItems().add(new ServiceView());
when(catalogServiceV2.listService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "serviceName", 1,
10, false)).thenReturn(result);
ServiceListForm serviceListForm = new ServiceListForm();

View File

@ -18,6 +18,7 @@
package com.alibaba.nacos.naming.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.pojo.maintainer.ServiceDetailInfo;
@ -191,10 +192,9 @@ class CatalogServiceV2ImplTest {
serviceInfo.setHosts(instances);
Mockito.when(serviceStorage.getData(Mockito.any())).thenReturn(serviceInfo);
List<ServiceDetailInfo> result = (List<ServiceDetailInfo>) catalogServiceV2Impl.pageListServiceDetail("A",
"B", "C", 1, 10);
Page<ServiceDetailInfo> result = catalogServiceV2Impl.pageListServiceDetail("A", "B", "C", 1, 10);
assertEquals(1, result.size());
assertEquals(1, result.getPageItems().size());
} catch (NacosException e) {
e.printStackTrace();
fail(e.getMessage());

View File

@ -22,13 +22,12 @@ import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import jakarta.servlet.http.HttpServletRequest;
/**
@ -39,14 +38,14 @@ import jakarta.servlet.http.HttpServletRequest;
*/
public class AbstractAuthenticationManager implements IAuthenticationManager {
protected NacosUserDetailsServiceImpl userDetailsService;
protected NacosUserService userDetailsService;
protected TokenManagerDelegate jwtTokenManager;
protected NacosRoleServiceImpl roleService;
protected NacosRoleService roleService;
public AbstractAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService) {
public AbstractAuthenticationManager(NacosUserService userDetailsService, TokenManagerDelegate jwtTokenManager,
NacosRoleService roleService) {
this.userDetailsService = userDetailsService;
this.jwtTokenManager = jwtTokenManager;
this.roleService = roleService;

View File

@ -16,9 +16,9 @@
package com.alibaba.nacos.plugin.auth.impl.authenticate;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
/**
* DefaultAuthenticationManager.
@ -28,8 +28,8 @@ import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
*/
public class DefaultAuthenticationManager extends AbstractAuthenticationManager {
public DefaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService) {
public DefaultAuthenticationManager(NacosUserService userDetailsService, TokenManagerDelegate jwtTokenManager,
NacosRoleService roleService) {
super(userDetailsService, jwtTokenManager, roleService);
}
}

View File

@ -21,11 +21,11 @@ import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.security.core.userdetails.UserDetails;
@ -45,8 +45,8 @@ public class LdapAuthenticationManager extends AbstractAuthenticationManager {
private final LdapTemplate ldapTemplate;
public LdapAuthenticationManager(LdapTemplate ldapTemplate, NacosUserDetailsServiceImpl userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService, String filterPrefix,
public LdapAuthenticationManager(LdapTemplate ldapTemplate, NacosUserService userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleService roleService, String filterPrefix,
boolean caseSensitive) {
super(userDetailsService, jwtTokenManager, roleService);
this.ldapTemplate = ldapTemplate;
@ -80,7 +80,7 @@ public class LdapAuthenticationManager extends AbstractAuthenticationManager {
userDetails = userDetailsService.loadUserByUsername(AuthConstants.LDAP_PREFIX + username);
} catch (UsernameNotFoundException exception) {
String ldapUsername = AuthConstants.LDAP_PREFIX + username;
userDetailsService.createUser(ldapUsername, AuthConstants.LDAP_DEFAULT_ENCODED_PASSWORD);
userDetailsService.createUser(ldapUsername, AuthConstants.LDAP_DEFAULT_ENCODED_PASSWORD, false);
User user = new User();
user.setUsername(ldapUsername);
user.setPassword(AuthConstants.LDAP_DEFAULT_ENCODED_PASSWORD);

View File

@ -23,12 +23,12 @@ import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.plugin.auth.impl.authenticate.DefaultAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthSystemTypes;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManager;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.token.impl.CachedJwtTokenManager;
import com.alibaba.nacos.plugin.auth.impl.token.impl.JwtTokenManager;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
@ -48,11 +48,11 @@ import javax.annotation.PostConstruct;
@Configuration
public class NacosAuthPluginConfig {
private final NacosUserDetailsServiceImpl userDetailsService;
private final NacosUserService userDetailsService;
private final ControllerMethodsCache methodsCache;
public NacosAuthPluginConfig(NacosUserDetailsServiceImpl userDetailsService, ControllerMethodsCache methodsCache) {
public NacosAuthPluginConfig(NacosUserService userDetailsService, ControllerMethodsCache methodsCache) {
this.userDetailsService = userDetailsService;
this.methodsCache = methodsCache;
@ -88,8 +88,8 @@ public class NacosAuthPluginConfig {
@Bean
@ConditionalOnMissingBean
public IAuthenticationManager defaultAuthenticationManager(NacosUserDetailsServiceImpl userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleServiceImpl roleService) {
public IAuthenticationManager defaultAuthenticationManager(NacosUserService userDetailsService,
TokenManagerDelegate jwtTokenManager, NacosRoleService roleService) {
return new DefaultAuthenticationManager(userDetailsService, jwtTokenManager, roleService);
}

View File

@ -79,4 +79,13 @@ public class AuthConstants {
public static final String LDAP_DEFAULT_ENCODED_PASSWORD = PasswordEncoderUtil.encode(System.getProperty("ldap.default.password", "nacos"));
public static final String LDAP_PREFIX = "LDAP_";
/**
* Path for nacos plugin controller.
*/
public static final String USER_PATH = "/v3/auth/user";
public static final String ROLE_PATH = "/v3/auth/role";
public static final String PERMISSION_PATH = "/v3/auth/permission";
}

View File

@ -16,17 +16,17 @@
package com.alibaba.nacos.plugin.auth.impl.controller;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@ -46,7 +46,7 @@ import org.springframework.web.bind.annotation.RestController;
public class PermissionController {
@Autowired
private NacosRoleServiceImpl nacosRoleService;
private NacosRoleService nacosRoleService;
/**
* Query permissions of a role.
@ -61,9 +61,9 @@ public class PermissionController {
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/permission/list")
public Object getPermissions(@RequestParam int pageNo, @RequestParam int pageSize,
@RequestParam(name = "role", defaultValue = StringUtils.EMPTY) String role) {
return nacosRoleService.getPermissionsFromDatabase(role, pageNo, pageSize);
return nacosRoleService.getPermissions(role, pageNo, pageSize);
}
/**
* Fuzzy Query permissions of a role.
*
@ -77,7 +77,7 @@ public class PermissionController {
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/permission/list")
public Page<PermissionInfo> fuzzySearchPermission(@RequestParam int pageNo, @RequestParam int pageSize,
@RequestParam(name = "role", defaultValue = StringUtils.EMPTY) String role) {
return nacosRoleService.findPermissionsLike4Page(role, pageNo, pageSize);
return nacosRoleService.findPermissions(role, pageNo, pageSize);
}
/**
@ -112,7 +112,7 @@ public class PermissionController {
nacosRoleService.deletePermission(role, resource, action);
return RestResultUtils.success("delete permission ok!");
}
/**
* Judge whether a permission is duplicate.
*
@ -124,7 +124,8 @@ public class PermissionController {
@GetMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.READ)
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/permission")
public Result<Boolean> isDuplicatePermission(@RequestParam String role, @RequestParam String resource, @RequestParam String action) {
public Result<Boolean> isDuplicatePermission(@RequestParam String role, @RequestParam String resource,
@RequestParam String action) {
return nacosRoleService.isDuplicatePermission(role, resource, action);
}
}

View File

@ -16,16 +16,16 @@
package com.alibaba.nacos.plugin.auth.impl.controller;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@ -47,7 +47,7 @@ import java.util.List;
public class RoleController {
@Autowired
private NacosRoleServiceImpl roleService;
private NacosRoleService roleService;
/**
* Get roles list.
@ -64,9 +64,9 @@ public class RoleController {
public Object getRoles(@RequestParam int pageNo, @RequestParam int pageSize,
@RequestParam(name = "username", defaultValue = "") String username,
@RequestParam(name = "role", defaultValue = "") String role) {
return roleService.getRolesFromDatabase(username, role, pageNo, pageSize);
return roleService.getRoles(username, role, pageNo, pageSize);
}
/**
* Fuzzy query role information.
* @param pageNo number index of page
@ -81,7 +81,7 @@ public class RoleController {
public Page<RoleInfo> fuzzySearchRole(@RequestParam int pageNo, @RequestParam int pageSize,
@RequestParam(name = "username", defaultValue = "") String username,
@RequestParam(name = "role", defaultValue = "") String role) {
return roleService.findRolesLike4Page(username, role, pageNo, pageSize);
return roleService.findRoles(username, role, pageNo, pageSize);
}
/**
@ -94,7 +94,7 @@ public class RoleController {
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.READ)
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/role/search")
public List<String> searchRoles(@RequestParam String role) {
return roleService.findRolesLikeRoleName(role);
return roleService.findRoleNames(role);
}
/**

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.plugin.auth.impl.controller;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.model.RestResultUtils;
@ -24,7 +25,6 @@ import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.context.RequestContextHolder;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
@ -34,13 +34,14 @@ 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.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordGeneratorUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
@ -57,8 +58,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@ -80,10 +79,10 @@ public class UserController {
private AuthenticationManager authenticationManager;
@Autowired
private NacosUserDetailsServiceImpl userDetailsService;
private NacosUserService userDetailsService;
@Autowired
private NacosRoleServiceImpl roleService;
private NacosRoleService roleService;
@Autowired
private AuthConfigs authConfigs;
@ -109,11 +108,11 @@ public class UserController {
"User `nacos` is default admin user. Please use `/nacos/v1/auth/users/admin` API to init `nacos` users. "
+ "Detail see `https://nacos.io/docs/latest/manual/admin/auth/#31-%E8%AE%BE%E7%BD%AE%E7%AE%A1%E7%90%86%E5%91%98%E5%AF%86%E7%A0%81`");
}
User user = userDetailsService.getUserFromDatabase(username);
User user = userDetailsService.getUser(username);
if (user != null) {
throw new IllegalArgumentException("user '" + username + "' already exist!");
}
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
userDetailsService.createUser(username, password);
return RestResultUtils.success("create user ok!");
}
@ -132,7 +131,7 @@ public class UserController {
}
String username = AuthConstants.DEFAULT_USER;
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
userDetailsService.createUser(username, password);
roleService.addAdminRole(username);
ObjectNode result = JacksonUtils.createEmptyJsonNode();
result.put(AuthConstants.PARAM_USERNAME, username);
@ -197,12 +196,12 @@ public class UserController {
return null;
}
User user = userDetailsService.getUserFromDatabase(username);
User user = userDetailsService.getUser(username);
if (user == null) {
throw new IllegalArgumentException("user " + username + " not exist!");
}
userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
userDetailsService.updateUserPassword(username, newPassword);
return RestResultUtils.success("update user ok!");
}
@ -246,7 +245,7 @@ public class UserController {
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/user/list")
public Page<User> getUsers(@RequestParam int pageNo, @RequestParam int pageSize,
@RequestParam(name = "username", required = false, defaultValue = "") String username) {
return userDetailsService.getUsersFromDatabase(pageNo, pageSize, username);
return userDetailsService.getUsers(pageNo, pageSize, username);
}
@GetMapping(params = "search=blur")
@ -254,7 +253,7 @@ public class UserController {
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/user/list")
public Page<User> fuzzySearchUser(@RequestParam int pageNo, @RequestParam int pageSize,
@RequestParam(name = "username", required = false, defaultValue = "") String username) {
return userDetailsService.findUsersLike4Page(username, pageNo, pageSize);
return userDetailsService.findUsers(username, pageNo, pageSize);
}
/**
@ -318,6 +317,6 @@ public class UserController {
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
@Compatibility(apiType = ApiType.CONSOLE_API, alternatives = "GET ${contextPath:nacos}/v3/auth/user/search")
public List<String> searchUsersLikeUsername(@RequestParam String username) {
return userDetailsService.findUserLikeUsername(username);
return userDetailsService.findUserNames(username);
}
}

View File

@ -17,16 +17,16 @@
package com.alibaba.nacos.plugin.auth.impl.controller.v3;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.paramcheck.ConfigDefaultHttpParamExtractor;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@ -41,11 +41,11 @@ import org.springframework.web.bind.annotation.RestController;
* @author zhangyukun on:2024/8/16
*/
@RestController
@RequestMapping("/v3/auth/permission")
@RequestMapping(AuthConstants.PERMISSION_PATH)
@ExtractorManager.Extractor(httpExtractor = ConfigDefaultHttpParamExtractor.class)
public class PermissionControllerV3 {
private final NacosRoleServiceImpl nacosRoleService;
private final NacosRoleService nacosRoleService;
private static final String SEARCH_TYPE_BLUR = "blur";
@ -55,7 +55,7 @@ public class PermissionControllerV3 {
* @param nacosRoleService nacosRoleService instance
*/
@Autowired
public PermissionControllerV3(NacosRoleServiceImpl nacosRoleService) {
public PermissionControllerV3(NacosRoleService nacosRoleService) {
this.nacosRoleService = nacosRoleService;
}
@ -69,12 +69,12 @@ public class PermissionControllerV3 {
*/
@PostMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.WRITE)
public Result<String> createPermission(@RequestParam String role, @RequestParam String resource, @RequestParam String action) {
public Result<String> createPermission(@RequestParam String role, @RequestParam String resource,
@RequestParam String action) {
nacosRoleService.addPermission(role, resource, action);
return Result.success("add permission ok!");
}
/**
* Delete a permission from a role.
*
@ -107,9 +107,9 @@ public class PermissionControllerV3 {
@RequestParam(name = "search", defaultValue = "accurate") String search) {
Page<PermissionInfo> permissionPage;
if (SEARCH_TYPE_BLUR.equalsIgnoreCase(search)) {
permissionPage = nacosRoleService.findPermissionsLike4Page(role, pageNo, pageSize);
permissionPage = nacosRoleService.findPermissions(role, pageNo, pageSize);
} else {
permissionPage = nacosRoleService.getPermissionsFromDatabase(role, pageNo, pageSize);
permissionPage = nacosRoleService.getPermissions(role, pageNo, pageSize);
}
return Result.success(permissionPage);
}
@ -124,7 +124,8 @@ public class PermissionControllerV3 {
*/
@GetMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.READ)
public Result<Boolean> isDuplicatePermission(@RequestParam String role, @RequestParam String resource, @RequestParam String action) {
public Result<Boolean> isDuplicatePermission(@RequestParam String role, @RequestParam String resource,
@RequestParam String action) {
return nacosRoleService.isDuplicatePermission(role, resource, action);
}
}

View File

@ -17,16 +17,16 @@
package com.alibaba.nacos.plugin.auth.impl.controller.v3;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.paramcheck.ConfigDefaultHttpParamExtractor;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -42,15 +42,15 @@ import java.util.List;
* @author zhangyukun on:2024/8/16
*/
@RestController
@RequestMapping("/v3/auth/role")
@RequestMapping(AuthConstants.ROLE_PATH)
@ExtractorManager.Extractor(httpExtractor = ConfigDefaultHttpParamExtractor.class)
public class RoleControllerV3 {
private final NacosRoleServiceImpl roleService;
private final NacosRoleService roleService;
private static final String SEARCH_TYPE_BLUR = "blur";
public RoleControllerV3(NacosRoleServiceImpl roleService) {
public RoleControllerV3(NacosRoleService roleService) {
this.roleService = roleService;
}
@ -107,9 +107,9 @@ public class RoleControllerV3 {
@RequestParam(name = "search", required = false, defaultValue = "accurate") String search) {
Page<RoleInfo> rolePage;
if (SEARCH_TYPE_BLUR.equalsIgnoreCase(search)) {
rolePage = roleService.findRolesLike4Page(username, role, pageNo, pageSize);
rolePage = roleService.findRoles(username, role, pageNo, pageSize);
} else {
rolePage = roleService.getRolesFromDatabase(username, role, pageNo, pageSize);
rolePage = roleService.getRoles(username, role, pageNo, pageSize);
}
return Result.success(rolePage);
}
@ -123,7 +123,7 @@ public class RoleControllerV3 {
@GetMapping("/search")
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.READ)
public Result<List<String>> getRoleListByRoleName(@RequestParam String role) {
List<String> roles = roleService.findRolesLikeRoleName(role);
List<String> roles = roleService.findRoleNames(role);
return Result.success(roles);
}
}

View File

@ -18,6 +18,7 @@
package com.alibaba.nacos.plugin.auth.impl.controller.v3;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
@ -26,7 +27,6 @@ import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.paramcheck.ConfigDefaultHttpParamExtractor;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
@ -35,11 +35,10 @@ 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.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordGeneratorUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.http.HttpServletRequest;
@ -63,13 +62,13 @@ import java.util.List;
* @author zhangyukun on:2024/8/16
*/
@RestController
@RequestMapping("/v3/auth/user")
@RequestMapping(AuthConstants.USER_PATH)
@ExtractorManager.Extractor(httpExtractor = ConfigDefaultHttpParamExtractor.class)
public class UserControllerV3 {
private final NacosUserDetailsServiceImpl userDetailsService;
private final NacosUserService userDetailsService;
private final NacosRoleServiceImpl roleService;
private final NacosRoleService roleService;
private final AuthConfigs authConfigs;
@ -88,9 +87,8 @@ public class UserControllerV3 {
* @param iAuthenticationManager the authentication manager interface
* @param jwtTokenManager the JWT token manager
*/
public UserControllerV3(NacosUserDetailsServiceImpl userDetailsService, NacosRoleServiceImpl roleService,
AuthConfigs authConfigs, IAuthenticationManager iAuthenticationManager,
TokenManagerDelegate jwtTokenManager) {
public UserControllerV3(NacosUserService userDetailsService, NacosRoleService roleService, AuthConfigs authConfigs,
IAuthenticationManager iAuthenticationManager, TokenManagerDelegate jwtTokenManager) {
this.userDetailsService = userDetailsService;
this.roleService = roleService;
this.authConfigs = authConfigs;
@ -110,11 +108,11 @@ public class UserControllerV3 {
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
@PostMapping
public Result<String> createUser(@RequestParam String username, @RequestParam String password) {
User user = userDetailsService.getUserFromDatabase(username);
User user = userDetailsService.getUser(username);
if (user != null) {
throw new IllegalArgumentException("user '" + username + "' already exist!");
}
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
userDetailsService.createUser(username, password);
return Result.success("create user ok!");
}
@ -133,7 +131,7 @@ public class UserControllerV3 {
return Result.failure(HttpStatus.CONFLICT.value(), "have admin user cannot use it.", null);
}
String username = AuthConstants.DEFAULT_USER;
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
userDetailsService.createUser(username, password);
roleService.addAdminRole(username);
User result = new User();
result.setUsername(username);
@ -195,12 +193,12 @@ public class UserControllerV3 {
return null;
}
User user = userDetailsService.getUserFromDatabase(username);
User user = userDetailsService.getUser(username);
if (user == null) {
throw new IllegalArgumentException("user " + username + " not exist!");
}
userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
userDetailsService.updateUserPassword(username, newPassword);
return Result.success("update user ok!");
}
@ -249,9 +247,9 @@ public class UserControllerV3 {
@RequestParam(name = "search", required = false, defaultValue = "accurate") String search) {
Page<User> userPage;
if (SEARCH_TYPE_BLUR.equalsIgnoreCase(search)) {
userPage = userDetailsService.findUsersLike4Page(username, pageNo, pageSize);
userPage = userDetailsService.findUsers(username, pageNo, pageSize);
} else {
userPage = userDetailsService.getUsersFromDatabase(pageNo, pageSize, username);
userPage = userDetailsService.getUsers(pageNo, pageSize, username);
}
return Result.success(userPage);
}
@ -265,7 +263,7 @@ public class UserControllerV3 {
@GetMapping("/search")
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
public Result<List<String>> getUserListByUsername(@RequestParam String username) {
List<String> userList = userDetailsService.findUserLikeUsername(username);
List<String> userList = userDetailsService.findUserNames(username);
return Result.success(userList);
}

View File

@ -20,9 +20,9 @@ import com.alibaba.nacos.plugin.auth.impl.authenticate.IAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.authenticate.LdapAuthenticationManager;
import com.alibaba.nacos.plugin.auth.impl.configuration.ConditionOnLdapAuth;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
@ -85,15 +85,14 @@ public class LdapAuthPluginConfig {
@Bean
public LdapAuthenticationProvider ldapAuthenticationProvider(LdapTemplate ldapTemplate,
NacosUserDetailsServiceImpl userDetailsService, NacosRoleServiceImpl nacosRoleService) {
NacosUserService userDetailsService, NacosRoleService nacosRoleService) {
return new LdapAuthenticationProvider(ldapTemplate, userDetailsService, nacosRoleService, filterPrefix,
caseSensitive);
}
@Bean
public IAuthenticationManager ldapAuthenticatoinManager(LdapTemplate ldapTemplate,
NacosUserDetailsServiceImpl userDetailsService, TokenManagerDelegate jwtTokenManager,
NacosRoleServiceImpl roleService) {
NacosUserService userDetailsService, TokenManagerDelegate jwtTokenManager, NacosRoleService roleService) {
return new LdapAuthenticationManager(ldapTemplate, userDetailsService, jwtTokenManager, roleService,
filterPrefix, caseSensitive);
}

View File

@ -21,9 +21,9 @@ import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.ldap.core.LdapTemplate;
@ -44,9 +44,9 @@ import java.util.List;
@Deprecated
public class LdapAuthenticationProvider implements AuthenticationProvider {
private final NacosUserDetailsServiceImpl userDetailsService;
private final NacosUserService userDetailsService;
private final NacosRoleServiceImpl nacosRoleService;
private final NacosRoleService nacosRoleService;
private final LdapTemplate ldapTemplate;
@ -54,8 +54,8 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
private final boolean caseSensitive;
public LdapAuthenticationProvider(LdapTemplate ldapTemplate, NacosUserDetailsServiceImpl userDetailsService,
NacosRoleServiceImpl nacosRoleService, String filterPrefix, boolean caseSensitive) {
public LdapAuthenticationProvider(LdapTemplate ldapTemplate, NacosUserService userDetailsService,
NacosRoleService nacosRoleService, String filterPrefix, boolean caseSensitive) {
this.ldapTemplate = ldapTemplate;
this.nacosRoleService = nacosRoleService;
this.userDetailsService = userDetailsService;
@ -94,7 +94,8 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
try {
userDetails = userDetailsService.loadUserByUsername(AuthConstants.LDAP_PREFIX + username);
} catch (UsernameNotFoundException exception) {
userDetailsService.createUser(AuthConstants.LDAP_PREFIX + username, AuthConstants.LDAP_DEFAULT_ENCODED_PASSWORD);
userDetailsService.createUser(AuthConstants.LDAP_PREFIX + username,
AuthConstants.LDAP_DEFAULT_ENCODED_PASSWORD, false);
User user = new User();
user.setUsername(AuthConstants.LDAP_PREFIX + username);
user.setPassword(AuthConstants.LDAP_DEFAULT_ENCODED_PASSWORD);

View File

@ -0,0 +1,89 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.roles;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Nacos abstract cached role service.
*
* @author xiweng.yy
*/
@Service
public abstract class AbstractCachedRoleService implements NacosRoleService {
protected static final int DEFAULT_PAGE_NO = 1;
private volatile Set<String> roleSet = new ConcurrentHashSet<>();
private volatile Map<String, List<RoleInfo>> roleInfoMap = new ConcurrentHashMap<>();
private volatile Map<String, List<PermissionInfo>> permissionInfoMap = new ConcurrentHashMap<>();
protected Set<String> getCachedRoleSet() {
return roleSet;
}
protected Map<String, List<RoleInfo>> getCachedRoleInfoMap() {
return roleInfoMap;
}
protected Map<String, List<PermissionInfo>> getCachedPermissionInfoMap() {
return permissionInfoMap;
}
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
protected void reload() {
try {
List<RoleInfo> roleInfoPage = getAllRoles();
Set<String> tmpRoleSet = new HashSet<>(16);
Map<String, List<RoleInfo>> tmpRoleInfoMap = new ConcurrentHashMap<>(16);
for (RoleInfo roleInfo : roleInfoPage) {
if (!tmpRoleInfoMap.containsKey(roleInfo.getUsername())) {
tmpRoleInfoMap.put(roleInfo.getUsername(), new ArrayList<>());
}
tmpRoleInfoMap.get(roleInfo.getUsername()).add(roleInfo);
tmpRoleSet.add(roleInfo.getRole());
}
Map<String, List<PermissionInfo>> tmpPermissionInfoMap = new ConcurrentHashMap<>(16);
for (String role : tmpRoleSet) {
Page<PermissionInfo> permissionInfoPage = getPermissions(role, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
tmpPermissionInfoMap.put(role, permissionInfoPage.getPageItems());
}
roleSet = tmpRoleSet;
roleInfoMap = tmpRoleInfoMap;
permissionInfoMap = tmpPermissionInfoMap;
} catch (Exception e) {
Loggers.AUTH.warn("[LOAD-ROLES] load failed", e);
}
}
}

View File

@ -0,0 +1,165 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.roles;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_NAMESPACE_ID;
/**
* Nacos abstract cached role service.
*
* @author xiweng.yy
*/
@Service
public abstract class AbstractCheckedRoleService extends AbstractCachedRoleService implements NacosRoleService {
private final AuthConfigs authConfigs;
protected AbstractCheckedRoleService(AuthConfigs authConfigs) {
this.authConfigs = authConfigs;
}
@Override
public boolean hasPermission(NacosUser nacosUser, Permission permission) {
if (isUpdatePasswordPermission(permission)) {
return true;
}
List<RoleInfo> roleInfoList = getRoles(nacosUser.getUserName());
if (CollectionUtils.isEmpty(roleInfoList)) {
return false;
}
// Global admin pass:
for (RoleInfo roleInfo : roleInfoList) {
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole())) {
nacosUser.setGlobalAdmin(true);
return true;
}
}
// Old global admin can pass resource 'console/':
if (permission.getResource().getName().startsWith(AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX)) {
return false;
}
// For other roles, use a pattern match to decide if pass or not.
for (RoleInfo roleInfo : roleInfoList) {
List<PermissionInfo> permissionInfoList = getPermissions(roleInfo.getRole());
if (CollectionUtils.isEmpty(permissionInfoList)) {
continue;
}
for (PermissionInfo permissionInfo : permissionInfoList) {
String permissionResource = permissionInfo.getResource().replaceAll("\\*", ".*");
String permissionAction = permissionInfo.getAction();
if (permissionAction.contains(permission.getAction()) && Pattern.matches(permissionResource,
joinResource(permission.getResource()))) {
return true;
}
}
}
return false;
}
@Override
public Result<Boolean> isDuplicatePermission(String role, String resource, String action) {
List<PermissionInfo> permissionInfos = getPermissions(role);
if (CollectionUtils.isEmpty(permissionInfos)) {
return Result.success(Boolean.FALSE);
}
for (PermissionInfo permissionInfo : permissionInfos) {
boolean resourceMatch = StringUtils.equals(resource, permissionInfo.getResource());
boolean actionMatch =
StringUtils.equals(action, permissionInfo.getAction()) || "rw".equals(permissionInfo.getAction());
if (resourceMatch && actionMatch) {
return Result.success(Boolean.TRUE);
}
}
return Result.success(Boolean.FALSE);
}
@Override
public boolean hasGlobalAdminRole(String userName) {
List<RoleInfo> roles = getRoles(userName);
return roles.stream().anyMatch(roleInfo -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole()));
}
@Override
public boolean hasGlobalAdminRole() {
if (authConfigs.isHasGlobalAdminRole()) {
return true;
}
List<RoleInfo> roles = getAllRoles();
boolean hasGlobalAdminRole = CollectionUtils.isNotEmpty(roles) && roles.stream()
.anyMatch(roleInfo -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole()));
authConfigs.setHasGlobalAdminRole(hasGlobalAdminRole);
return hasGlobalAdminRole;
}
/**
* If API is update user password, don't do permission check, because there is permission check in API logic.
*/
private boolean isUpdatePasswordPermission(Permission permission) {
Properties properties = permission.getResource().getProperties();
return null != properties && properties.contains(AuthConstants.UPDATE_PASSWORD_ENTRY_POINT);
}
private String joinResource(Resource resource) {
if (SignType.SPECIFIED.equals(resource.getType())) {
return resource.getName();
}
StringBuilder result = new StringBuilder();
String namespaceId = resource.getNamespaceId();
if (StringUtils.isNotBlank(namespaceId)) {
// https://github.com/alibaba/nacos/issues/10347
if (!DEFAULT_NAMESPACE_ID.equals(namespaceId)) {
result.append(namespaceId);
}
}
String group = resource.getGroup();
if (StringUtils.isBlank(group)) {
result.append(Constants.Resource.SPLITTER).append('*');
} else {
result.append(Constants.Resource.SPLITTER).append(group);
}
String resourceName = resource.getName();
if (StringUtils.isBlank(resourceName)) {
result.append(Constants.Resource.SPLITTER).append(resource.getType().toLowerCase()).append("/*");
} else {
result.append(Constants.Resource.SPLITTER).append(resource.getType().toLowerCase()).append('/')
.append(resourceName);
}
return result.toString();
}
}

View File

@ -0,0 +1,192 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.roles;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import java.util.List;
/**
* Nacos auth plugin role service interface.
*
* @author xiweng.yy
*/
public interface NacosRoleService {
/**
* Determine if the user has permission of the resource.
*
* <p>Note if the user has many roles, this method returns true if any one role of the user has the desired
* permission.
*
* @param nacosUser user info
* @param permission permission to auth
* @return true if granted, false otherwise
*/
boolean hasPermission(NacosUser nacosUser, Permission permission);
/**
* Add permission to tole.
*
* @param role role name
* @param resource resource
* @param action action
*/
void addPermission(String role, String resource, String action);
/**
* Delete permission from role.
*
* @param role role name
* @param resource resource
* @param action action
*/
void deletePermission(String role, String resource, String action);
/**
* Get all permissions of the role.
*
* @param role role name
* @return List of {@link PermissionInfo} for the role
*/
List<PermissionInfo> getPermissions(String role);
/**
* Accurate search permissions by role name pattern.
*
* @param role role name pattern
* @param pageNo page number
* @param pageSize page size
* @return List of {@link RoleInfo} match role name pattern
*/
Page<PermissionInfo> getPermissions(String role, int pageNo, int pageSize);
/**
* Blur search permissions by role name pattern.
*
* @param role role name pattern
* @param pageNo page number
* @param pageSize page size
* @return List of {@link RoleInfo} match role name pattern
*/
Page<PermissionInfo> findPermissions(String role, int pageNo, int pageSize);
/**
* Judge whether the permission is duplicate.
*
* @param role role name
* @param resource resource
* @param action action
* @return true if duplicate, false otherwise
*/
Result<Boolean> isDuplicatePermission(String role, String resource, String action);
/**
* Get All roles for target user.
*
* @param username username of target user
* @return List of {@link RoleInfo} for target user
*/
List<RoleInfo> getRoles(String username);
/**
* Accurate search roles by role name pattern.
*
* @param username username of target user
* @param role role name
* @param pageNo page number
* @param pageSize page size
* @return List of {@link RoleInfo} match role name pattern
*/
Page<RoleInfo> getRoles(String username, String role, int pageNo, int pageSize);
/**
* Blur search roles by role name pattern.
*
* @param username username of target user
* @param role role name pattern
* @param pageNo page number
* @param pageSize page size
* @return List of {@link RoleInfo} match role name pattern
*/
Page<RoleInfo> findRoles(String username, String role, int pageNo, int pageSize);
/**
* Blur search role names by role name pattern.
*
* @param role role name pattern
* @return List of {@link RoleInfo} match role name pattern
*/
List<String> findRoleNames(String role);
/**
* Get All roles in Nacos.
*
* @return List of {@link RoleInfo} in Nacos
*/
List<RoleInfo> getAllRoles();
/**
* Add role to user.
*
* @param role role name
* @param username user name
*/
void addRole(String role, String username);
/**
* Delete Role from user.
*
* @param role role
* @param userName userName
*/
void deleteRole(String role, String userName);
/**
* Delete Role from Nacos.
*
* @param role role
*/
void deleteRole(String role);
/**
* Add role.
*
* @param username user name
*/
void addAdminRole(String username);
/**
* Check if user has admin role.
*
* @param userName user name
* @return true if user has admin role.
*/
boolean hasGlobalAdminRole(String userName);
/**
* Check if all user has at least one admin role.
*
* @return true if all user has at least one admin role.
*/
boolean hasGlobalAdminRole();
}

View File

@ -0,0 +1,201 @@
/*
* 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.plugin.auth.impl.roles;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionPersistService;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.RolePersistService;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Nacos builtin role service, implemented by directly access to database.
*
* @author nkorange
* @since 1.2.0
*/
@Service
public class NacosRoleServiceDirectImpl extends AbstractCheckedRoleService implements NacosRoleService {
private static final int DEFAULT_PAGE_NO = 1;
private final AuthConfigs authConfigs;
private final RolePersistService rolePersistService;
private final NacosUserService userDetailsService;
private final PermissionPersistService permissionPersistService;
public NacosRoleServiceDirectImpl(AuthConfigs authConfigs, RolePersistService rolePersistService,
NacosUserService userDetailsService, PermissionPersistService permissionPersistService) {
super(authConfigs);
this.authConfigs = authConfigs;
this.rolePersistService = rolePersistService;
this.userDetailsService = userDetailsService;
this.permissionPersistService = permissionPersistService;
}
@Override
public List<RoleInfo> getRoles(String username) {
List<RoleInfo> roleInfoList = getCachedRoleInfoMap().get(username);
if (!authConfigs.isCachingEnabled() || roleInfoList == null) {
Page<RoleInfo> roleInfoPage = getRoles(username, StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
if (roleInfoPage != null) {
roleInfoList = roleInfoPage.getPageItems();
if (!CollectionUtils.isEmpty(roleInfoList)) {
getCachedRoleInfoMap().put(username, roleInfoList);
}
}
}
return roleInfoList;
}
@Override
public Page<RoleInfo> getRoles(String username, String role, int pageNo, int pageSize) {
Page<RoleInfo> roles = rolePersistService.getRolesByUserNameAndRoleName(username, role, pageNo, pageSize);
if (roles == null) {
return new Page<>();
}
return roles;
}
@Override
public List<RoleInfo> getAllRoles() {
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserNameAndRoleName(StringUtils.EMPTY,
StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
if (roleInfoPage == null) {
return null;
}
return roleInfoPage.getPageItems();
}
@Override
public List<PermissionInfo> getPermissions(String role) {
List<PermissionInfo> permissionInfoList = getCachedPermissionInfoMap().get(role);
if (!authConfigs.isCachingEnabled() || permissionInfoList == null) {
Page<PermissionInfo> permissionInfoPage = getPermissions(role, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
if (permissionInfoPage != null) {
permissionInfoList = permissionInfoPage.getPageItems();
if (!CollectionUtils.isEmpty(permissionInfoList)) {
getCachedPermissionInfoMap().put(role, permissionInfoList);
}
}
}
return permissionInfoList;
}
@Override
public Page<PermissionInfo> getPermissions(String role, int pageNo, int pageSize) {
Page<PermissionInfo> pageInfo = permissionPersistService.getPermissions(role, pageNo, pageSize);
if (pageInfo == null) {
return new Page<>();
}
return pageInfo;
}
@Override
public void addRole(String role, String username) {
if (userDetailsService.getUser(username) == null) {
throw new IllegalArgumentException("user '" + username + "' not found!");
}
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
throw new IllegalArgumentException(
"role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' is not permitted to create!");
}
if (isUserBoundToRole(role, username)) {
throw new IllegalArgumentException("user '" + username + "' already bound to the role '" + role + "'!");
}
rolePersistService.addRole(role, username);
getCachedRoleSet().add(role);
}
@Override
public void addAdminRole(String username) {
if (userDetailsService.getUser(username) == null) {
throw new IllegalArgumentException("user '" + username + "' not found!");
}
if (hasGlobalAdminRole()) {
throw new IllegalArgumentException("role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' already exist !");
}
rolePersistService.addRole(AuthConstants.GLOBAL_ADMIN_ROLE, username);
getCachedRoleSet().add(AuthConstants.GLOBAL_ADMIN_ROLE);
authConfigs.setHasGlobalAdminRole(true);
}
@Override
public void deleteRole(String role, String userName) {
rolePersistService.deleteRole(role, userName);
}
@Override
public void deleteRole(String role) {
rolePersistService.deleteRole(role);
getCachedRoleInfoMap().remove(role);
}
@Override
public void addPermission(String role, String resource, String action) {
if (!getCachedRoleSet().contains(role)) {
throw new IllegalArgumentException("role " + role + " not found!");
}
permissionPersistService.addPermission(role, resource, action);
}
@Override
public void deletePermission(String role, String resource, String action) {
permissionPersistService.deletePermission(role, resource, action);
}
@Override
public Page<RoleInfo> findRoles(String username, String role, int pageNo, int pageSize) {
return rolePersistService.findRolesLike4Page(username, role, pageNo, pageSize);
}
@Override
public List<String> findRoleNames(String role) {
return rolePersistService.findRolesLikeRoleName(role);
}
@Override
public Page<PermissionInfo> findPermissions(String role, int pageNo, int pageSize) {
return permissionPersistService.findPermissionsLike4Page(role, pageNo, pageSize);
}
boolean isUserBoundToRole(String role, String username) {
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserNameAndRoleName(username, role, DEFAULT_PAGE_NO,
1);
if (roleInfoPage == null) {
return false;
}
List<RoleInfo> roleInfos = roleInfoPage.getPageItems();
return CollectionUtils.isNotEmpty(roleInfos) && roleInfos.stream()
.anyMatch(roleInfo -> role.equals(roleInfo.getRole()));
}
}

View File

@ -1,422 +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.plugin.auth.impl.roles;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionPersistService;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.RolePersistService;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_NAMESPACE_ID;
/**
* Nacos builtin role service.
*
* @author nkorange
* @since 1.2.0
*/
@Service
public class NacosRoleServiceImpl {
private static final int DEFAULT_PAGE_NO = 1;
@Autowired
private AuthConfigs authConfigs;
@Autowired
private RolePersistService rolePersistService;
@Autowired
private NacosUserDetailsServiceImpl userDetailsService;
@Autowired
private PermissionPersistService permissionPersistService;
private volatile Set<String> roleSet = new ConcurrentHashSet<>();
private volatile Map<String, List<RoleInfo>> roleInfoMap = new ConcurrentHashMap<>();
private volatile Map<String, List<PermissionInfo>> permissionInfoMap = new ConcurrentHashMap<>();
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
private void reload() {
try {
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserNameAndRoleName(StringUtils.EMPTY,
StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
if (roleInfoPage == null) {
return;
}
Set<String> tmpRoleSet = new HashSet<>(16);
Map<String, List<RoleInfo>> tmpRoleInfoMap = new ConcurrentHashMap<>(16);
for (RoleInfo roleInfo : roleInfoPage.getPageItems()) {
if (!tmpRoleInfoMap.containsKey(roleInfo.getUsername())) {
tmpRoleInfoMap.put(roleInfo.getUsername(), new ArrayList<>());
}
tmpRoleInfoMap.get(roleInfo.getUsername()).add(roleInfo);
tmpRoleSet.add(roleInfo.getRole());
}
Map<String, List<PermissionInfo>> tmpPermissionInfoMap = new ConcurrentHashMap<>(16);
for (String role : tmpRoleSet) {
Page<PermissionInfo> permissionInfoPage = permissionPersistService.getPermissions(role, DEFAULT_PAGE_NO,
Integer.MAX_VALUE);
tmpPermissionInfoMap.put(role, permissionInfoPage.getPageItems());
}
roleSet = tmpRoleSet;
roleInfoMap = tmpRoleInfoMap;
permissionInfoMap = tmpPermissionInfoMap;
} catch (Exception e) {
Loggers.AUTH.warn("[LOAD-ROLES] load failed", e);
}
}
/**
* Determine if the user has permission of the resource.
*
* <p>Note if the user has many roles, this method returns true if any one role of the user has the desired
* permission.
*
* @param nacosUser user info
* @param permission permission to auth
* @return true if granted, false otherwise
*/
public boolean hasPermission(NacosUser nacosUser, Permission permission) {
if (isUpdatePasswordPermission(permission)) {
return true;
}
List<RoleInfo> roleInfoList = getRoles(nacosUser.getUserName());
if (CollectionUtils.isEmpty(roleInfoList)) {
return false;
}
// Global admin pass:
for (RoleInfo roleInfo : roleInfoList) {
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole())) {
nacosUser.setGlobalAdmin(true);
return true;
}
}
// Old global admin can pass resource 'console/':
if (permission.getResource().getName().startsWith(AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX)) {
return false;
}
// For other roles, use a pattern match to decide if pass or not.
for (RoleInfo roleInfo : roleInfoList) {
List<PermissionInfo> permissionInfoList = getPermissions(roleInfo.getRole());
if (CollectionUtils.isEmpty(permissionInfoList)) {
continue;
}
for (PermissionInfo permissionInfo : permissionInfoList) {
String permissionResource = permissionInfo.getResource().replaceAll("\\*", ".*");
String permissionAction = permissionInfo.getAction();
if (permissionAction.contains(permission.getAction()) && Pattern.matches(permissionResource,
joinResource(permission.getResource()))) {
return true;
}
}
}
return false;
}
/**
* If API is update user password, don't do permission check, because there is permission check in API logic.
*/
private boolean isUpdatePasswordPermission(Permission permission) {
Properties properties = permission.getResource().getProperties();
return null != properties && properties.contains(AuthConstants.UPDATE_PASSWORD_ENTRY_POINT);
}
public List<RoleInfo> getRoles(String username) {
List<RoleInfo> roleInfoList = roleInfoMap.get(username);
if (!authConfigs.isCachingEnabled() || roleInfoList == null) {
Page<RoleInfo> roleInfoPage = getRolesFromDatabase(username, StringUtils.EMPTY, DEFAULT_PAGE_NO,
Integer.MAX_VALUE);
if (roleInfoPage != null) {
roleInfoList = roleInfoPage.getPageItems();
if (!CollectionUtils.isEmpty(roleInfoList)) {
roleInfoMap.put(username, roleInfoList);
}
}
}
return roleInfoList;
}
public List<RoleInfo> getAllRoles() {
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserNameAndRoleName(StringUtils.EMPTY,
StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
if (roleInfoPage == null) {
return null;
}
return roleInfoPage.getPageItems();
}
public Page<RoleInfo> getRolesFromDatabase(String userName, String role, int pageNo, int pageSize) {
Page<RoleInfo> roles = rolePersistService.getRolesByUserNameAndRoleName(userName, role, pageNo, pageSize);
if (roles == null) {
return new Page<>();
}
return roles;
}
public List<PermissionInfo> getPermissions(String role) {
List<PermissionInfo> permissionInfoList = permissionInfoMap.get(role);
if (!authConfigs.isCachingEnabled() || permissionInfoList == null) {
Page<PermissionInfo> permissionInfoPage = getPermissionsFromDatabase(role, DEFAULT_PAGE_NO,
Integer.MAX_VALUE);
if (permissionInfoPage != null) {
permissionInfoList = permissionInfoPage.getPageItems();
if (!CollectionUtils.isEmpty(permissionInfoList)) {
permissionInfoMap.put(role, permissionInfoList);
}
}
}
return permissionInfoList;
}
public Page<PermissionInfo> getPermissionsByRoleFromDatabase(String role, int pageNo, int pageSize) {
return permissionPersistService.getPermissions(role, pageNo, pageSize);
}
/**
* Add role.
*
* @param role role name
* @param username user name
*/
public void addRole(String role, String username) {
if (userDetailsService.getUserFromDatabase(username) == null) {
throw new IllegalArgumentException("user '" + username + "' not found!");
}
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
throw new IllegalArgumentException(
"role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' is not permitted to create!");
}
if (isUserBoundToRole(role, username)) {
throw new IllegalArgumentException(
"user '" + username + "' already bound to the role '" + role + "'!");
}
rolePersistService.addRole(role, username);
roleSet.add(role);
}
/**
* Add role.
*
* @param username user name
*/
public void addAdminRole(String username) {
if (userDetailsService.getUserFromDatabase(username) == null) {
throw new IllegalArgumentException("user '" + username + "' not found!");
}
if (hasGlobalAdminRole()) {
throw new IllegalArgumentException("role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' already exist !");
}
rolePersistService.addRole(AuthConstants.GLOBAL_ADMIN_ROLE, username);
roleSet.add(AuthConstants.GLOBAL_ADMIN_ROLE);
authConfigs.setHasGlobalAdminRole(true);
}
/**
* delete user Role.
*
* @param role role
* @param userName userName
*/
public void deleteRole(String role, String userName) {
rolePersistService.deleteRole(role, userName);
}
/**
* deleteRole.
*
* @param role role
*/
public void deleteRole(String role) {
rolePersistService.deleteRole(role);
roleSet.remove(role);
}
public Page<PermissionInfo> getPermissionsFromDatabase(String role, int pageNo, int pageSize) {
Page<PermissionInfo> pageInfo = permissionPersistService.getPermissions(role, pageNo, pageSize);
if (pageInfo == null) {
return new Page<>();
}
return pageInfo;
}
/**
* Add permission.
*
* @param role role name
* @param resource resource
* @param action action
*/
public void addPermission(String role, String resource, String action) {
if (!roleSet.contains(role)) {
throw new IllegalArgumentException("role " + role + " not found!");
}
permissionPersistService.addPermission(role, resource, action);
}
public void deletePermission(String role, String resource, String action) {
permissionPersistService.deletePermission(role, resource, action);
}
public List<String> findRolesLikeRoleName(String role) {
return rolePersistService.findRolesLikeRoleName(role);
}
private String joinResource(Resource resource) {
if (SignType.SPECIFIED.equals(resource.getType())) {
return resource.getName();
}
StringBuilder result = new StringBuilder();
String namespaceId = resource.getNamespaceId();
if (StringUtils.isNotBlank(namespaceId)) {
// https://github.com/alibaba/nacos/issues/10347
if (!DEFAULT_NAMESPACE_ID.equals(namespaceId)) {
result.append(namespaceId);
}
}
String group = resource.getGroup();
if (StringUtils.isBlank(group)) {
result.append(Constants.Resource.SPLITTER).append('*');
} else {
result.append(Constants.Resource.SPLITTER).append(group);
}
String resourceName = resource.getName();
if (StringUtils.isBlank(resourceName)) {
result.append(Constants.Resource.SPLITTER).append(resource.getType().toLowerCase()).append("/*");
} else {
result.append(Constants.Resource.SPLITTER).append(resource.getType().toLowerCase()).append('/')
.append(resourceName);
}
return result.toString();
}
public Page<RoleInfo> findRolesLike4Page(String username, String role, int pageNo, int pageSize) {
return rolePersistService.findRolesLike4Page(username, role, pageNo, pageSize);
}
public Page<PermissionInfo> findPermissionsLike4Page(String role, int pageNo, int pageSize) {
return permissionPersistService.findPermissionsLike4Page(role, pageNo, pageSize);
}
/**
* check if user has admin role.
*
* @param userName user name
* @return true if user has admin role.
*/
public boolean hasGlobalAdminRole(String userName) {
List<RoleInfo> roles = getRoles(userName);
return roles.stream().anyMatch(roleInfo -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole()));
}
/**
* check if all user has at least one admin role.
*
* @return true if all user has at least one admin role.
*/
public boolean hasGlobalAdminRole() {
if (authConfigs.isHasGlobalAdminRole()) {
return true;
}
List<RoleInfo> roles = getAllRoles();
boolean hasGlobalAdminRole = CollectionUtils.isNotEmpty(roles) && roles.stream()
.anyMatch(roleInfo -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole()));
authConfigs.setHasGlobalAdminRole(hasGlobalAdminRole);
return hasGlobalAdminRole;
}
/**
* judge whether the permission is duplicate.
*
* @param role role name
* @param resource resource
* @param action action
* @return true if duplicate, false otherwise
*/
public Result<Boolean> isDuplicatePermission(String role, String resource, String action) {
List<PermissionInfo> permissionInfos = getPermissions(role);
if (CollectionUtils.isEmpty(permissionInfos)) {
return Result.success(Boolean.FALSE);
}
for (PermissionInfo permissionInfo : permissionInfos) {
boolean resourceMatch = StringUtils.equals(resource, permissionInfo.getResource());
boolean actionMatch = StringUtils.equals(action, permissionInfo.getAction()) || "rw".equals(permissionInfo.getAction());
if (resourceMatch && actionMatch) {
return Result.success(Boolean.TRUE);
}
}
return Result.success(Boolean.FALSE);
}
/**
* judge whether the user is already bound to the role.
*
* @param role role name
* @param username user name
* @return true if the user is already bound to the role.
*/
public boolean isUserBoundToRole(String role, String username) {
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserNameAndRoleName(username,
role, DEFAULT_PAGE_NO, 1);
if (roleInfoPage == null) {
return false;
}
List<RoleInfo> roleInfos = roleInfoPage.getPageItems();
return CollectionUtils.isNotEmpty(roleInfos) && roleInfos.stream()
.anyMatch(roleInfo -> role.equals(roleInfo.getRole()));
}
}

View File

@ -0,0 +1,261 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.roles;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.constant.RequestUrlConstants;
import com.alibaba.nacos.common.http.DefaultHttpClientFactory;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.persistence.RoleInfo;
import com.alibaba.nacos.plugin.auth.impl.utils.RemoteServerUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
/**
* Nacos builtin role service, implemented by remote request to nacos server.
*
* @author xiweng.yy
*/
public class NacosRoleServiceRemoteImpl extends AbstractCheckedRoleService implements NacosRoleService {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosRoleServiceRemoteImpl.class);
private final NacosRestTemplate nacosRestTemplate;
private final AuthConfigs authConfigs;
public NacosRoleServiceRemoteImpl(AuthConfigs authConfigs) {
super(authConfigs);
this.authConfigs = authConfigs;
this.nacosRestTemplate = new DefaultHttpClientFactory(LOGGER).createNacosRestTemplate();
}
@Override
public void addPermission(String role, String resource, String action) {
Map<String, String> body = Map.of("role", role, "resource", resource, "action", action);
try {
HttpRestResult<String> result = nacosRestTemplate.postForm(
buildRemotePermissionUrlPath(AuthConstants.PERMISSION_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), null, body, String.class);
RemoteServerUtil.singleCheckResult(result);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public void deletePermission(String role, String resource, String action) {
Query query = Query.newInstance().addParam("role", role).addParam("resource", resource)
.addParam("action", action);
try {
HttpRestResult<String> result = nacosRestTemplate.delete(
buildRemotePermissionUrlPath(AuthConstants.PERMISSION_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(result);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public List<PermissionInfo> getPermissions(String role) {
if (getCachedPermissionInfoMap().containsKey(role)) {
return getCachedPermissionInfoMap().get(role);
}
reload();
return getCachedPermissionInfoMap().get(role);
}
@Override
public Page<PermissionInfo> getPermissions(String role, int pageNo, int pageSize) {
Query query = Query.newInstance().addParam("role", role).addParam("pageNo", pageNo)
.addParam("pageSize", pageSize).addParam("search", "accurate");
return getPermissionInfoPageFromRemote(query);
}
@Override
public Page<PermissionInfo> findPermissions(String role, int pageNo, int pageSize) {
Query query = Query.newInstance().addParam("role", role).addParam("pageNo", pageNo)
.addParam("pageSize", pageSize).addParam("search", "blur");
return getPermissionInfoPageFromRemote(query);
}
@Override
public List<RoleInfo> getRoles(String username) {
if (getCachedRoleInfoMap().containsKey(username)) {
return getCachedRoleInfoMap().get(username);
}
reload();
return getCachedRoleInfoMap().get(username);
}
@Override
public Page<RoleInfo> getRoles(String username, String role, int pageNo, int pageSize) {
Query query = Query.newInstance().addParam("username", username).addParam("role", role)
.addParam("pageNo", pageNo).addParam("pageSize", pageSize).addParam("search", "accurate");
return getRoleInfoPageFromRemote(query);
}
@Override
public Page<RoleInfo> findRoles(String username, String role, int pageNo, int pageSize) {
Query query = Query.newInstance().addParam("username", username).addParam("role", role)
.addParam("pageNo", pageNo).addParam("pageSize", pageSize).addParam("search", "blur");
return getRoleInfoPageFromRemote(query);
}
@Override
public List<String> findRoleNames(String role) {
Query query = Query.newInstance().addParam("role", role);
try {
HttpRestResult<String> httpResult = nacosRestTemplate.get(
buildRemoteRoleUrlPath(AuthConstants.ROLE_PATH + "/search"),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(httpResult);
Result<List<String>> result = JacksonUtils.toObj(httpResult.getData(), new TypeReference<>() {
});
return result.getData();
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public List<RoleInfo> getAllRoles() {
return getRoles(StringUtils.EMPTY, StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE).getPageItems();
}
@Override
public void addRole(String role, String username) {
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
throw new IllegalArgumentException(
"role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' is not permitted to create!");
}
Map<String, String> body = Map.of("role", role, "username", username);
try {
HttpRestResult<String> httpResult = nacosRestTemplate.postForm(
buildRemoteRoleUrlPath(AuthConstants.ROLE_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), body, String.class);
RemoteServerUtil.singleCheckResult(httpResult);
getCachedRoleSet().add(role);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public void deleteRole(String role, String userName) {
Query query = Query.newInstance().addParam("role", role).addParam("userName", userName);
try {
HttpRestResult<String> result = nacosRestTemplate.delete(buildRemoteRoleUrlPath(AuthConstants.ROLE_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(result);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public void deleteRole(String role) {
Query query = Query.newInstance().addParam("role", role);
try {
HttpRestResult<String> result = nacosRestTemplate.delete(buildRemoteRoleUrlPath(AuthConstants.ROLE_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(result);
getCachedRoleSet().remove(role);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public void addAdminRole(String username) {
if (hasGlobalAdminRole()) {
throw new IllegalArgumentException("role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' already exist !");
}
addRole(AuthConstants.GLOBAL_ADMIN_ROLE, username);
getCachedRoleSet().add(AuthConstants.GLOBAL_ADMIN_ROLE);
authConfigs.setHasGlobalAdminRole(true);
}
private String buildRemotePermissionUrlPath(String apiPath) {
return RequestUrlConstants.HTTP_PREFIX + RemoteServerUtil.getOneNacosServerAddress()
+ RemoteServerUtil.getRemoteServerContextPath() + apiPath;
}
private Page<PermissionInfo> getPermissionInfoPageFromRemote(Query query) {
try {
HttpRestResult<String> httpResult = nacosRestTemplate.get(
buildRemotePermissionUrlPath(AuthConstants.PERMISSION_PATH + "/list"),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(httpResult);
Result<Page<PermissionInfo>> result = JacksonUtils.toObj(httpResult.getData(), new TypeReference<>() {
});
return result.getData();
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
private String buildRemoteRoleUrlPath(String apiPath) {
return RequestUrlConstants.HTTP_PREFIX + RemoteServerUtil.getOneNacosServerAddress()
+ RemoteServerUtil.getRemoteServerContextPath() + apiPath;
}
private Page<RoleInfo> getRoleInfoPageFromRemote(Query query) {
try {
HttpRestResult<String> httpResult = nacosRestTemplate.get(
buildRemoteRoleUrlPath(AuthConstants.ROLE_PATH + "/list"),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(httpResult);
Result<Page<RoleInfo>> result = JacksonUtils.toObj(httpResult.getData(), new TypeReference<>() {
});
return result.getData();
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.users;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Nacos abstract cached user service.
*
* @author xiweng.yy
*/
@Service
public abstract class AbstractCachedUserService implements NacosUserService {
private Map<String, User> userMap = new ConcurrentHashMap<>();
protected AbstractCachedUserService() {
}
protected Map<String, User> getCachedUserMap() {
return userMap;
}
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
protected void reload() {
try {
Page<User> users = getUsers(1, Integer.MAX_VALUE, StringUtils.EMPTY);
if (users == null) {
return;
}
Map<String, User> map = new ConcurrentHashMap<>(16);
for (User user : users.getPageItems()) {
map.put(user.getUsername(), user);
}
userMap = map;
} catch (Exception e) {
Loggers.AUTH.warn("[LOAD-USERS] load failed", e);
}
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.users;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.List;
/**
* Nacos auth plugin user service interface.
*
* @author xiweng.yy
*/
public interface NacosUserService extends UserDetailsService {
/**
* Update user password.
*
* @param username username to be updated password
* @param password new password
*/
void updateUserPassword(String username, String password);
/**
* Get users by paged.
*
* @param pageNo page number
* @param pageSize page size
* @param username username
* @return user list
*/
Page<User> getUsers(int pageNo, int pageSize, String username);
/**
* Find users with blur search by paged.
*
* @param username username
* @param pageNo page number
* @param pageSize page size
* @return user list
*/
Page<User> findUsers(String username, int pageNo, int pageSize);
/**
* Get User info by username.
*
* @param username username
* @return {@link User} information
*/
User getUser(String username);
/**
* Find usernames with blur search.
*
* @param username username
* @return usernames
*/
List<String> findUserNames(String username);
/**
* Create user.
*
* @param username username
* @param password password
*/
default void createUser(String username, String password) {
createUser(username, password, true);
}
/**
* Create user.
*
* @param username username
* @param password password
* @param encode {@code true} will encode password, {@code false} will not encode password
*/
void createUser(String username, String password, boolean encode);
/**
* Delete user.
*
* @param username username
*/
void deleteUser(String username);
}

View File

@ -16,109 +16,83 @@
package com.alibaba.nacos.plugin.auth.impl.users;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.auth.impl.persistence.UserPersistService;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import com.alibaba.nacos.plugin.auth.impl.persistence.UserPersistService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import org.springframework.security.core.userdetails.UserDetails;
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;
/**
* Custom user service.
* Custom user service, implemented by directly access to database.
*
* @author wfnuser
* @author nkorange
*/
@Service
public class NacosUserDetailsServiceImpl implements UserDetailsService {
public class NacosUserServiceDirectImpl extends AbstractCachedUserService implements NacosUserService {
private Map<String, User> userMap = new ConcurrentHashMap<>();
private final UserPersistService userPersistService;
@Autowired
private UserPersistService userPersistService;
private final AuthConfigs authConfigs;
@Autowired
private AuthConfigs authConfigs;
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
private void reload() {
try {
Page<User> users = getUsersFromDatabase(1, Integer.MAX_VALUE, StringUtils.EMPTY);
if (users == null) {
return;
}
Map<String, User> map = new ConcurrentHashMap<>(16);
for (User user : users.getPageItems()) {
map.put(user.getUsername(), user);
}
userMap = map;
} catch (Exception e) {
Loggers.AUTH.warn("[LOAD-USERS] load failed", e);
}
public NacosUserServiceDirectImpl(AuthConfigs authConfigs, UserPersistService userPersistService) {
super();
this.userPersistService = userPersistService;
this.authConfigs = authConfigs;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMap.get(username);
User user = getCachedUserMap().get(username);
if (!authConfigs.isCachingEnabled()) {
user = userPersistService.findUserByUsername(username);
user = getUser(username);
}
if (user == null) {
throw new UsernameNotFoundException(String.format("User %s not found", username));
}
return new NacosUserDetails(user);
}
@Override
public void updateUserPassword(String username, String password) {
userPersistService.updateUserPassword(username, password);
userPersistService.updateUserPassword(username, PasswordEncoderUtil.encode(password));
}
public Page<User> getUsersFromDatabase(int pageNo, int pageSize, String username) {
@Override
public Page<User> getUsers(int pageNo, int pageSize, String username) {
return userPersistService.getUsers(pageNo, pageSize, username);
}
@Override
public User getUser(String username) {
User user = userMap.get(username);
if (!authConfigs.isCachingEnabled() || user == null) {
user = getUserFromDatabase(username);
if (user != null) {
userMap.put(username, user);
}
}
return user;
}
public User getUserFromDatabase(String username) {
return userPersistService.findUserByUsername(username);
}
public List<String> findUserLikeUsername(String username) {
@Override
public List<String> findUserNames(String username) {
return userPersistService.findUserLikeUsername(username);
}
public void createUser(String username, String password) {
@Override
public void createUser(String username, String password, boolean encode) {
if (encode) {
password = PasswordEncoderUtil.encode(password);
}
userPersistService.createUser(username, password);
}
@Override
public void deleteUser(String username) {
userPersistService.deleteUser(username);
}
public Page<User> findUsersLike4Page(String username, int pageNo, int pageSize) {
@Override
public Page<User> findUsers(String username, int pageNo, int pageSize) {
return userPersistService.findUsersLike4Page(username, pageNo, pageSize);
}
}

View File

@ -0,0 +1,176 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.users;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.constant.RequestUrlConstants;
import com.alibaba.nacos.common.http.DefaultHttpClientFactory;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.utils.RemoteServerUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.List;
import java.util.Map;
/**
* Custom user service, implemented by remote request to nacos server.
*
* @author xiweng.yy
*/
public class NacosUserServiceRemoteImpl extends AbstractCachedUserService implements NacosUserService {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosUserServiceRemoteImpl.class);
private final NacosRestTemplate nacosRestTemplate;
private final AuthConfigs authConfigs;
public NacosUserServiceRemoteImpl(AuthConfigs authConfigs) {
super();
this.authConfigs = authConfigs;
this.nacosRestTemplate = new DefaultHttpClientFactory(LOGGER).createNacosRestTemplate();
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = getUser(username);
if (null == user) {
throw new UsernameNotFoundException(String.format("User %s not found", username));
}
return new NacosUserDetails(user);
}
@Override
public void updateUserPassword(String username, String password) {
Query query = Query.newInstance().addParam("username", username);
Map<String, String> body = Map.of("newPassword", password);
try {
HttpRestResult<String> result = nacosRestTemplate.putForm(buildRemoteUserUrlPath(AuthConstants.USER_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, body, String.class);
RemoteServerUtil.singleCheckResult(result);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public Page<User> getUsers(int pageNo, int pageSize, String username) {
Query query = Query.newInstance().addParam("username", username).addParam("pageNo", pageNo)
.addParam("pageSize", pageSize).addParam("search", "accurate");
return getUserPageFromRemote(query);
}
@Override
public Page<User> findUsers(String username, int pageNo, int pageSize) {
Query query = Query.newInstance().addParam("username", username).addParam("pageNo", pageNo)
.addParam("pageSize", pageSize).addParam("search", "blur");
return getUserPageFromRemote(query);
}
@Override
public User getUser(String username) {
if (getCachedUserMap().containsKey(username)) {
return getCachedUserMap().get(username);
}
reload();
return getCachedUserMap().get(username);
}
@Override
public List<String> findUserNames(String username) {
Query query = Query.newInstance().addParam("username", username);
try {
HttpRestResult<String> httpResult = nacosRestTemplate.get(
buildRemoteUserUrlPath(AuthConstants.USER_PATH + "/search"),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(httpResult);
Result<List<String>> result = JacksonUtils.toObj(httpResult.getData(), new TypeReference<>() {
});
return result.getData();
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public void createUser(String username, String password, boolean encode) {
// ignore encode = true, let nacos server do encode
Query query = Query.newInstance().addParam("username", username);
Map<String, String> body = Map.of("password", password);
try {
HttpRestResult<String> result = nacosRestTemplate.postForm(buildRemoteUserUrlPath(AuthConstants.USER_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, body, String.class);
RemoteServerUtil.singleCheckResult(result);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
@Override
public void deleteUser(String username) {
Query query = Query.newInstance().addParam("username", username);
try {
HttpRestResult<String> result = nacosRestTemplate.delete(buildRemoteUserUrlPath(AuthConstants.USER_PATH),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(result);
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
private String buildRemoteUserUrlPath(String apiPath) {
return RequestUrlConstants.HTTP_PREFIX + RemoteServerUtil.getOneNacosServerAddress()
+ RemoteServerUtil.getRemoteServerContextPath() + apiPath;
}
private Page<User> getUserPageFromRemote(Query query) {
try {
HttpRestResult<String> httpResult = nacosRestTemplate.get(
buildRemoteUserUrlPath(AuthConstants.USER_PATH + "/list"),
RemoteServerUtil.buildServerRemoteHeader(authConfigs), query, String.class);
RemoteServerUtil.singleCheckResult(httpResult);
Result<Page<User>> result = JacksonUtils.toObj(httpResult.getData(), new TypeReference<>() {
});
return result.getData();
} catch (NacosException e) {
throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
} catch (Exception unpectedException) {
throw new NacosRuntimeException(NacosException.SERVER_ERROR, unpectedException.getMessage());
}
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright 1999-2025 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.plugin.auth.impl.utils;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.file.FileChangeEvent;
import com.alibaba.nacos.sys.file.FileWatcher;
import com.alibaba.nacos.sys.file.WatchFileCenter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Nacos auth plugin remote nacos server util.
*
* @author xiweng.yy
*/
public class RemoteServerUtil {
private static List<String> serverAddresses = new LinkedList<>();
private static AtomicInteger index = new AtomicInteger();
private static String remoteServerContextPath = "/nacos";
static {
readRemoteServerAddress();
registerWatcher();
initRemoteServerContextPath();
}
private static void initRemoteServerContextPath() {
remoteServerContextPath = EnvUtil.getProperty("nacos.console.remote.server.context-path", "/nacos");
}
private static void registerWatcher() {
try {
WatchFileCenter.registerWatcher(EnvUtil.getClusterConfFilePath(), new FileWatcher() {
@Override
public void onChange(FileChangeEvent event) {
readRemoteServerAddress();
}
@Override
public boolean interest(String context) {
return true;
}
});
} catch (Exception ignored) {
}
}
/**
* Read nacos server address from cluster.conf.
*/
public static void readRemoteServerAddress() {
try {
serverAddresses = EnvUtil.readClusterConf();
} catch (IOException ignored) {
}
}
public static List<String> getServerAddresses() {
return new LinkedList<>(serverAddresses);
}
public static String getOneNacosServerAddress() {
int actual = index.getAndUpdate(operand -> (operand + 1) % serverAddresses.size());
return serverAddresses.get(actual);
}
public static String getRemoteServerContextPath() {
return remoteServerContextPath;
}
/**
* Single check http result, if not success, wrapper result as Nacos exception.
*
* @param result http execute result
* @throws NacosException wrapper result as NacosException
*/
public static void singleCheckResult(HttpRestResult<String> result) throws NacosException {
if (result.ok()) {
return;
}
throw new NacosException(result.getCode(), result.getMessage());
}
/**
* According input {@link AuthConfigs} to build remote server identity header.
*
* @param authConfigs authConfigs
* @return remote server identity header
*/
public static Header buildServerRemoteHeader(AuthConfigs authConfigs) {
Header header = Header.newInstance();
if (StringUtils.isNotBlank(authConfigs.getServerIdentityKey())) {
header.addParam(authConfigs.getServerIdentityKey(), authConfigs.getServerIdentityValue());
}
return header;
}
}

View File

@ -21,11 +21,11 @@ import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.constant.AuthConstants;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -48,13 +48,13 @@ public class AbstractAuthenticationManagerTest {
private AbstractAuthenticationManager abstractAuthenticationManager;
@Mock
private NacosUserDetailsServiceImpl userDetailsService;
private NacosUserService userDetailsService;
@Mock
private TokenManagerDelegate jwtTokenManager;
@Mock
private NacosRoleServiceImpl roleService;
private NacosRoleService roleService;
private User user;

View File

@ -18,11 +18,11 @@ package com.alibaba.nacos.plugin.auth.impl.authenticate;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetails;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserService;
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -39,13 +39,13 @@ import static org.mockito.Mockito.when;
public class LdapAuthenticationManagerTest {
@Mock
private NacosUserDetailsServiceImpl userDetailsService;
private NacosUserService userDetailsService;
@Mock
private TokenManagerDelegate jwtTokenManager;
@Mock
private NacosRoleServiceImpl roleService;
private NacosRoleService roleService;
@Mock
private LdapTemplate ldapTemplate;

View File

@ -16,11 +16,11 @@
package com.alibaba.nacos.plugin.auth.impl.controller;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.api.model.Page;
import com.alibaba.nacos.plugin.auth.impl.persistence.PermissionInfo;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.plugin.auth.impl.roles.NacosRoleService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -42,7 +42,7 @@ public class PermissionControllerTest {
private PermissionController permissionController;
@Mock
private NacosRoleServiceImpl nacosRoleService;
private NacosRoleService nacosRoleService;
@BeforeEach
void setUp() throws Exception {
@ -53,8 +53,7 @@ public class PermissionControllerTest {
void testGetPermissions() {
Page<PermissionInfo> permissionInfoPage = new Page<PermissionInfo>();
when(nacosRoleService.getPermissionsFromDatabase(anyString(), anyInt(), anyInt())).thenReturn(
permissionInfoPage);
when(nacosRoleService.getPermissions(anyString(), anyInt(), anyInt())).thenReturn(permissionInfoPage);
Object permissions = permissionController.getPermissions(1, 10, "admin");
assertEquals(permissionInfoPage, permissions);
@ -64,7 +63,7 @@ public class PermissionControllerTest {
void testFuzzySearchPermission() {
Page<PermissionInfo> permissionInfoPage = new Page<PermissionInfo>();
when(nacosRoleService.findPermissionsLike4Page(anyString(), anyInt(), anyInt())).thenReturn(permissionInfoPage);
when(nacosRoleService.findPermissions(anyString(), anyInt(), anyInt())).thenReturn(permissionInfoPage);
Page<PermissionInfo> permissions = permissionController.fuzzySearchPermission(1, 10, "admin");
assertEquals(permissionInfoPage, permissions);

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