ak auth support on long connection (#3821)

This commit is contained in:
nov.lzf 2020-09-14 16:47:59 +08:00 committed by GitHub
parent 35895cf5ae
commit d83a4b12b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 410 additions and 41 deletions

View File

@ -37,6 +37,11 @@ public class AddressServerAuthManager implements AuthManager {
return result;
}
@Override
public User loginRemote(Object request) throws AccessException {
return null;
}
@Override
public void auth(Permission permission, User user) throws AccessException {
}

View File

@ -17,7 +17,6 @@
package com.alibaba.nacos.api.config.remote.response;
import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.api.remote.response.ResponseCode;
import java.util.HashMap;
import java.util.Map;
@ -62,9 +61,7 @@ public class ConfigQueryResponse extends Response {
*/
public static ConfigQueryResponse buildFailResponse(int errorCode, String message) {
ConfigQueryResponse response = new ConfigQueryResponse();
response.setResultCode(ResponseCode.FAIL.getCode());
response.setErrorCode(errorCode);
response.setMessage(message);
response.setErrorInfo(errorCode, message);
return response;
}

View File

@ -52,8 +52,7 @@ public class ServiceListResponse extends Response {
*/
public static ServiceListResponse buildFailResponse(String message) {
ServiceListResponse result = new ServiceListResponse();
result.setErrorCode(ResponseCode.FAIL.getCode());
result.setMessage(message);
result.setErrorInfo(ResponseCode.FAIL.getCode(), message);
return result;
}

View File

@ -116,6 +116,12 @@ public abstract class Response {
this.errorCode = errorCode;
}
public void setErrorInfo(int errorCode, String errorMsg) {
this.resultCode = ResponseCode.FAIL.getCode();
this.errorCode = errorCode;
this.message = errorMsg;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);

View File

@ -38,6 +38,15 @@ public interface AuthManager {
*/
User login(Object request) throws AccessException;
/**
* Authentication of request, identify the user who request the resource.
*
* @param request where we can find the user information
* @return user related to this request, null if no user info is found.
* @throws AccessException if authentication is failed
*/
User loginRemote(Object request) throws AccessException;
/**
* Authorization of request, constituted with resource and user.
*

View File

@ -55,10 +55,15 @@ public class ConfigTest {
public void before() throws Exception {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
properties.setProperty("-Dclientworker.use.http.switch", "Y");
//properties.setProperty(PropertyKeyConst.SERVER_ADDR, "11.160.144.148:8848");
//properties.setProperty(PropertyKeyConst.SERVER_ADDR, "11.160.144.149:8848,11.160.144.148:8848,127.0.0.1:8848");
//"11.239.114.187:8848,,11.239.113.204:8848,11.239.112.161:8848");
//"11.239.114.187:8848");
properties.setProperty(PropertyKeyConst.USERNAME, "nacos");
properties.setProperty(PropertyKeyConst.PASSWORD, "nacos");
configService = NacosFactory.createConfigService(properties);
//Thread.sleep(2000L);
}
@ -249,8 +254,7 @@ public class ConfigTest {
try {
String content1 = System.currentTimeMillis() + "";
//System.out.println("publish content:" + content1);
configService.publishConfig(dataId, group, content1);
boolean b = configService.publishConfig(dataId, group, content1);
times--;
Thread.sleep(1000L);
} catch (Exception e) {

View File

@ -600,7 +600,7 @@ public abstract class RpcClient implements Closeable {
*
* @param serverRequestHandler serverRequestHandler
*/
public void registerServerPushResponseHandler(ServerRequestHandler serverRequestHandler) {
public synchronized void registerServerPushResponseHandler(ServerRequestHandler serverRequestHandler) {
LoggerUtils.printIfInfoEnabled(LOGGER,
" Registry server push response listener to current client, connectionEventListener={}",
serverRequestHandler.getClass().getName());

View File

@ -43,4 +43,21 @@ public class ReflectUtils {
}
}
/**
* get filed value of obj.
*
* @param obj obj.
* @param fieldName file name to get value.
* @return
*/
public static Object getFieldValue(Object obj, String fieldName, Object defaultValue) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
return defaultValue;
}
}
}

View File

@ -16,12 +16,14 @@
package com.alibaba.nacos.config.server.auth;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.auth.model.Resource;
import com.alibaba.nacos.auth.parser.ResourceParser;
import com.alibaba.nacos.common.utils.ReflectUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* Config resource parser.
*
@ -33,11 +35,22 @@ public class ConfigResourceParser implements ResourceParser {
private static final String AUTH_CONFIG_PREFIX = "config/";
@Override
public String parseName(Object request) {
HttpServletRequest req = (HttpServletRequest) request;
String namespaceId = req.getParameter("tenant");
String groupName = req.getParameter("group");
String dataId = req.getParameter("dataId");
public String parseName(Object requestObj) {
String namespaceId = null;
String groupName = null;
String dataId = null;
if (requestObj instanceof HttpServletRequest) {
HttpServletRequest req = (HttpServletRequest) requestObj;
namespaceId = req.getParameter("tenant");
groupName = req.getParameter("group");
dataId = req.getParameter("dataId");
} else if (requestObj instanceof Request) {
Request request = (Request) requestObj;
namespaceId = (String) ReflectUtils.getFieldValue(request, "tenant", "");
groupName = (String) ReflectUtils.getFieldValue(request, "group", "");
dataId = (String) ReflectUtils.getFieldValue(request, "dataId", "");
}
StringBuilder sb = new StringBuilder();

View File

@ -20,6 +20,9 @@ import com.alibaba.nacos.api.config.remote.request.ConfigRemoveRequest;
import com.alibaba.nacos.api.config.remote.response.ConfigRemoveResponse;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.config.server.auth.ConfigResourceParser;
import com.alibaba.nacos.config.server.model.event.ConfigDataChangeEvent;
import com.alibaba.nacos.config.server.service.ConfigChangePublisher;
import com.alibaba.nacos.config.server.service.repository.PersistService;
@ -47,6 +50,7 @@ public class ConfiRemoveRequestHandler extends RequestHandler<ConfigRemoveReques
private PersistService persistService;
@Override
@Secured(action = ActionTypes.WRITE, parser = ConfigResourceParser.class)
public ConfigRemoveResponse handle(ConfigRemoveRequest request, RequestMeta meta) throws NacosException {
ConfigRemoveRequest myrequest = (ConfigRemoveRequest) request;
// check tenant

View File

@ -20,6 +20,9 @@ import com.alibaba.nacos.api.config.remote.request.ConfigBatchListenRequest;
import com.alibaba.nacos.api.config.remote.response.ConfigChangeBatchListenResponse;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.config.server.auth.ConfigResourceParser;
import com.alibaba.nacos.config.server.service.ConfigCacheService;
import com.alibaba.nacos.config.server.utils.GroupKey2;
import com.alibaba.nacos.config.server.utils.SingletonRepository;
@ -43,6 +46,7 @@ public class ConfigChangeBatchListenRequestHandler
ConfigChangeListenContext configChangeListenContext;
@Override
@Secured(action = ActionTypes.READ, parser = ConfigResourceParser.class)
public ConfigChangeBatchListenResponse handle(ConfigBatchListenRequest request, RequestMeta requestMeta)
throws NacosException {
ConfigBatchListenRequest configChangeListenRequest = (ConfigBatchListenRequest) request;

View File

@ -56,7 +56,7 @@ public class ConfigPublishRequestHandler extends RequestHandler<ConfigPublishReq
private PersistService persistService;
@Override
@Secured(action = ActionTypes.WRITE, parser = ConfigResourceParser.class)
@Secured(action = ActionTypes.WRITE, resource = "", parser = ConfigResourceParser.class)
public ConfigPubishResponse handle(ConfigPublishRequest myRequest, RequestMeta meta) throws NacosException {
try {

View File

@ -21,6 +21,9 @@ import com.alibaba.nacos.api.config.remote.response.ConfigQueryResponse;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.api.remote.response.ResponseCode;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.config.server.auth.ConfigResourceParser;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.CacheItem;
import com.alibaba.nacos.config.server.model.ConfigInfoBase;
@ -64,6 +67,7 @@ public class ConfigQueryRequestHandler extends RequestHandler<ConfigQueryRequest
private PersistService persistService;
@Override
@Secured(action = ActionTypes.READ, parser = ConfigResourceParser.class)
public ConfigQueryResponse handle(ConfigQueryRequest request, RequestMeta requestMeta) throws NacosException {
ConfigQueryRequest configQueryRequest = (ConfigQueryRequest) request;
@ -161,8 +165,7 @@ public class ConfigQueryRequestHandler extends RequestHandler<ConfigQueryRequest
// no data",
// new Object[]{clientIp, groupKey});
response.setErrorCode(ConfigQueryResponse.CONFIG_NOT_FOUND);
response.setMessage("config data not exist");
response.setErrorInfo(ConfigQueryResponse.CONFIG_NOT_FOUND, "config data not exist");
return response;
}
}
@ -193,8 +196,7 @@ public class ConfigQueryRequestHandler extends RequestHandler<ConfigQueryRequest
// no data",
// new Object[]{clientIp, groupKey});
response.setErrorCode(ConfigQueryResponse.CONFIG_NOT_FOUND);
response.setMessage("config data not exist");
response.setErrorInfo(ConfigQueryResponse.CONFIG_NOT_FOUND, "config data not exist");
return response;
}
@ -238,14 +240,12 @@ public class ConfigQueryRequestHandler extends RequestHandler<ConfigQueryRequest
ConfigTraceService
.logPullEvent(dataId, group, tenant, requestIpApp, -1, ConfigTraceService.PULL_EVENT_NOTFOUND, -1,
clientIp);
response.setErrorCode(ConfigQueryResponse.CONFIG_NOT_FOUND);
response.setMessage("config data not exist");
response.setErrorInfo(ConfigQueryResponse.CONFIG_NOT_FOUND, "config data not exist");
} else {
PULL_LOG.info("[client-get] clientIp={}, {}, get data during dump", clientIp, groupKey);
response.setErrorCode(ConfigQueryResponse.CONFIG_QUERY_CONFLICT);
response.setMessage("requested file is being modified, please try later.");
response.setErrorInfo(ConfigQueryResponse.CONFIG_QUERY_CONFLICT,
"requested file is being modified, please try later.");
}
return response;
}

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.console.security.nacos;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.auth.AuthManager;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.Permission;
@ -95,6 +96,41 @@ public class NacosAuthManager implements AuthManager {
return user;
}
@Override
public User loginRemote(Object request) throws AccessException {
Request req = (Request) request;
String token = resolveToken(req);
if (StringUtils.isBlank(token)) {
throw new AccessException("user not found!");
}
try {
tokenManager.validateToken(token);
} catch (ExpiredJwtException e) {
throw new AccessException("token expired!");
} catch (Exception e) {
throw new AccessException("token invalid!");
}
Authentication authentication = tokenManager.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
String username = authentication.getName();
NacosUser user = new NacosUser();
user.setUserName(username);
user.setToken(token);
List<RoleInfo> roleInfoList = roleService.getRoles(username);
if (roleInfoList != null) {
for (RoleInfo roleInfo : roleInfoList) {
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
}
return user;
}
@Override
public void auth(Permission permission, User user) throws AccessException {
if (Loggers.AUTH.isDebugEnabled()) {
@ -124,6 +160,24 @@ public class NacosAuthManager implements AuthManager {
return bearerToken;
}
/**
* Get token from header.
*/
private String resolveToken(Request request) throws AccessException {
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7);
}
bearerToken = request.getHeader(Constants.ACCESS_TOKEN);
if (StringUtils.isBlank(bearerToken)) {
String userName = request.getHeader("username");
String password = request.getHeader("password");
bearerToken = resolveTokenFromUser(userName, password);
}
return bearerToken;
}
private String resolveTokenFromUser(String userName, String rawPassword) throws AccessException {
try {

View File

@ -0,0 +1,134 @@
/*
* Copyright 1999-2020 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.auth;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.auth.AuthManager;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.Permission;
import com.alibaba.nacos.auth.parser.ResourceParser;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.core.remote.RequestFilter;
import com.alibaba.nacos.core.utils.Loggers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* request auth filter for remote.
*
* @author liuzunfei
* @version $Id: RemoteRequestAuthFilter.java, v 0.1 2020年09月14日 12:38 PM liuzunfei Exp $
*/
@Component
public class RemoteRequestAuthFilter extends RequestFilter {
@Autowired
private AuthConfigs authConfigs;
@Autowired
private AuthManager authManager;
@Autowired
private ControllerMethodsCache methodsCache;
private Method getMethod(Class handlerClazz) throws NacosException {
try {
Method method = handlerClazz.getMethod("handle", Request.class, RequestMeta.class);
return method;
} catch (NoSuchMethodException e) {
throw new NacosException(NacosException.SERVER_ERROR, e);
}
}
private Class getResponseClazz(Class handlerClazz) throws NacosException {
ParameterizedType parameterizedType = (ParameterizedType) handlerClazz.getGenericSuperclass();
try {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
return Class.forName(actualTypeArguments[1].getTypeName());
} catch (Exception e) {
throw new NacosException(NacosException.SERVER_ERROR, e);
}
}
@Override
public Response filter(Request request, RequestMeta meta, Class handlerClazz) {
Response response = null;
try {
response = (Response) getResponseClazz(handlerClazz).newInstance();
} catch (Exception e) {
Loggers.AUTH.error("auth fail, request: {},exception:", request.getClass().getSimpleName(), e);
}
try {
Method method = getMethod(handlerClazz);
if (method.isAnnotationPresent(Secured.class) && authConfigs.isAuthEnabled()) {
if (Loggers.AUTH.isDebugEnabled()) {
Loggers.AUTH.debug("auth start, request: {}", request.getClass().getSimpleName());
}
Secured secured = method.getAnnotation(Secured.class);
String action = secured.action().toString();
String resource = secured.resource();
if (StringUtils.isBlank(resource)) {
ResourceParser parser = secured.parser().newInstance();
resource = parser.parseName(request);
}
if (StringUtils.isBlank(resource)) {
// deny if we don't find any resource:
throw new AccessException("resource name invalid!");
}
authManager.auth(new Permission(resource, action), authManager.loginRemote(request));
}
} catch (AccessException e) {
if (Loggers.AUTH.isDebugEnabled()) {
Loggers.AUTH.debug("access denied, request: {}, reason: {}", request.getClass().getSimpleName(),
e.getErrMsg());
}
response.setErrorInfo(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return response;
} catch (IllegalArgumentException e) {
response.setErrorInfo(HttpServletResponse.SC_BAD_REQUEST, ExceptionUtil.getAllExceptionMsg(e));
return response;
} catch (Exception e) {
response.setErrorInfo(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server failed," + e.getMessage());
return response;
}
return response;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2020 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.remote;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.api.remote.request.RequestMeta;
import com.alibaba.nacos.api.remote.response.Response;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
/**
* interceptor fo request.
*
* @author liuzunfei
* @version $Id: RequestFilter.java, v 0.1 2020年09月14日 11:46 AM liuzunfei Exp $
*/
public abstract class RequestFilter {
@Autowired
private RequestFilters requestFilters;
public RequestFilter() {
}
@PostConstruct
public void init() {
requestFilters.registerFilter(this);
}
/**
* filter request.
*
* @param request request.
* @param meta request meta.
* @return response
*/
protected abstract Response filter(Request request, RequestMeta meta, Class handlerClazz);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 1999-2020 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.remote;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* filters of request.
*
* @author liuzunfei
* @version $Id: RequestFilters.java, v 0.1 2020年09月14日 12:00 PM liuzunfei Exp $
*/
@Service
public class RequestFilters {
List<RequestFilter> filters = new ArrayList<RequestFilter>();
public void registerFilter(RequestFilter requestFilter) {
filters.add(requestFilter);
}
}

View File

@ -36,11 +36,32 @@ public abstract class RequestHandler<T extends Request, S extends Response> {
@Autowired
private RequestHandlerRegistry requestHandlerRegistry;
@Autowired
private RequestFilters requestFilters;
@PostConstruct
public void init() {
requestHandlerRegistry.registryHandler(this);
}
/**
* Handler request.
*
* @param request request
* @param meta request meta data
* @return response
* @throws NacosException nacos exception when handle request has problem.
*/
public Response handleRequest(T request, RequestMeta meta) throws NacosException {
for (RequestFilter filter : requestFilters.filters) {
Response filterResult = filter.filter(request, meta, this.getClass());
if (filterResult != null && !filterResult.isSuccess()) {
return filterResult;
}
}
return handle(request, meta);
}
/**
* Handler request.
*

View File

@ -78,7 +78,7 @@ public class GrpcRequestAcceptor extends RequestGrpc.RequestImplBase {
return;
}
connectionManager.refreshActiveTime(parseObj.getMetadata().getConnectionId());
Response response = requestHandler.handle(request, parseObj.getMetadata());
Response response = requestHandler.handleRequest(request, parseObj.getMetadata());
responseObserver.onNext(GrpcUtils.convert(response));
responseObserver.onCompleted();
return;
@ -102,8 +102,7 @@ public class GrpcRequestAcceptor extends RequestGrpc.RequestImplBase {
private Response buildFailResponse(String msg) {
UnKnowResponse response = new UnKnowResponse();
response.setErrorCode(ResponseCode.FAIL.getCode());
response.setMessage(msg);
response.setErrorInfo(ResponseCode.FAIL.getCode(), msg);
return response;
}

View File

@ -184,7 +184,7 @@ public class RsocketRpcServer extends BaseRpcServer {
RequestMeta requestMeta = requestType.getMetadata();
requestMeta.setConnectionId(connectionId);
try {
Response response = requestHandler.handle(requestType.getBody(), requestMeta);
Response response = requestHandler.handleRequest(requestType.getBody(), requestMeta);
return Mono.just(RsocketUtils.convertResponseToPayload(response));
} catch (NacosException e) {

View File

@ -18,8 +18,10 @@ package com.alibaba.nacos.naming.web;
import com.alibaba.nacos.api.naming.CommonParams;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.auth.model.Resource;
import com.alibaba.nacos.auth.parser.ResourceParser;
import com.alibaba.nacos.common.utils.ReflectUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
@ -35,13 +37,23 @@ public class NamingResourceParser implements ResourceParser {
private static final String AUTH_NAMING_PREFIX = "naming/";
@Override
public String parseName(Object request) {
public String parseName(Object requestObj) {
HttpServletRequest req = (HttpServletRequest) request;
String namespaceId = null;
String serviceName = null;
String groupName = null;
if (requestObj instanceof HttpServletRequest) {
HttpServletRequest req = (HttpServletRequest) requestObj;
namespaceId = req.getParameter(CommonParams.NAMESPACE_ID);
serviceName = req.getParameter(CommonParams.SERVICE_NAME);
groupName = req.getParameter(CommonParams.GROUP_NAME);
} else if (requestObj instanceof Request) {
Request request = (Request) requestObj;
namespaceId = (String) ReflectUtils.getFieldValue(request, "namespace", "");
groupName = (String) ReflectUtils.getFieldValue(request, "groupName", "");
serviceName = (String) ReflectUtils.getFieldValue(request, "serviceName", "");
}
String namespaceId = req.getParameter(CommonParams.NAMESPACE_ID);
String serviceName = req.getParameter(CommonParams.SERVICE_NAME);
String groupName = req.getParameter(CommonParams.GROUP_NAME);
if (StringUtils.isBlank(groupName)) {
groupName = NamingUtils.getGroupName(serviceName);
}