问题:在生产中使用 nacos 2.2.0(2.0.4) 开启鉴权后,发现配置文件中已经按照要求填写了 username 和 password 但是程序在启动时候依然出现,无法注册。
上面标注的两个版本是亲测,有问题的。至于其他版本如果发现相同问题,也可以按照下面的方式进行测试。
2023-12-13 12:56:04.684 ERROR 31588 --- [ main] c.a.c.n.registry.NacosServiceRegistry : nacos registry, managecenter-gateway register failed...NacosRegistration{nacosDiscoveryProperties=NacosDiscoveryProperties{serverAd
dr='192.168.119.249:8808', username='nacos', password='nacos', endpoint='', namespace='65e2e949-0bce-4d38-83fa-904a35b9cc78', watchDelay=30000, logName='', service='managecenter-gateway', weight=1.0, clusterName='DEFAULT', group='ma
nageCenter-test', namingLoadCacheAtStart='false', metadata={IPv6=[240e:31f:1624:d500:fc35:bdc2:ff0f:f1ef], preserved.register.source=SPRING_CLOUD}, registerEnabled=true, ip='192.168.119.10', networkInterface='', port=6007, secure=false, accessKey='', secretKey='', heartBeatInterval=null, heartBeatTimeout=null, ipDeleteTimeout=null, instanceEnabled=true, ephemeral=true, failureToleranceEnabled=false}, ipDeleteTimeout=null, failFast=true}},
com.alibaba.nacos.api.exception.NacosException: unknown user!
at com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy.requestToServer(NamingGrpcClientProxy.java:358) ~[nacos-client-2.2.0.jar!/:na]
at com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy.doRegisterService(NamingGrpcClientProxy.java:209) ~[nacos-client-2.2.0.jar!/:na]
at com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy.registerService(NamingGrpcClientProxy.java:123) ~[nacos-client-2.2.0.jar!/:na]
被问题困扰,于是开始排查,发现是由于没有拿到 accessToken 导致,注册失败。当找到 HttpLoginProcessor.java 时候发现 JsonNode obj = JacksonUtils.toObj(restResult.getData()); 没有返回!错误也没被抛出,不知道原因。
package com.alibaba.nacos.client.auth.impl.process;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.client.auth.impl.NacosAuthLoginConstant;
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
import com.alibaba.nacos.client.utils.ContextPathUtil;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import static com.alibaba.nacos.client.naming.utils.UtilAndComs.webContext;
import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTP_PREFIX;
/**
* Login processor for Http.
*
* @author Nacos
*/
public class HttpLoginProcessor implements LoginProcessor {
private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger(HttpLoginProcessor.class);
private static final String LOGIN_URL = "/v1/auth/users/login";
private final NacosRestTemplate nacosRestTemplate;
public HttpLoginProcessor(NacosRestTemplate nacosRestTemplate) {
this.nacosRestTemplate = nacosRestTemplate;
}
@Override
public LoginIdentityContext getResponse(Properties properties) {
String contextPath = ContextPathUtil
.normalizeContextPath(properties.getProperty(PropertyKeyConst.CONTEXT_PATH, webContext));
String server = properties.getProperty(NacosAuthLoginConstant.SERVER, StringUtils.EMPTY);
String url = HTTP_PREFIX + server + contextPath + LOGIN_URL;
if (server.contains(Constants.HTTP_PREFIX)) {
url = server + contextPath + LOGIN_URL;
}
Map<String, String> params = new HashMap<>(2);
Map<String, String> bodyMap = new HashMap<>(2);
params.put(PropertyKeyConst.USERNAME, properties.getProperty(PropertyKeyConst.USERNAME, StringUtils.EMPTY));
bodyMap.put(PropertyKeyConst.PASSWORD, properties.getProperty(PropertyKeyConst.PASSWORD, StringUtils.EMPTY));
try {
HttpRestResult<String> restResult = nacosRestTemplate
.postForm(url, Header.EMPTY, Query.newInstance().initParams(params), bodyMap, String.class);
if (!restResult.ok()) {
SECURITY_LOGGER.error("login failed: {}", JacksonUtils.toJson(restResult));
return null;
}
//发现这行下面没有返回,导致无法获取到token
JsonNode obj = JacksonUtils.toObj(restResult.getData());
LoginIdentityContext loginIdentityContext = new LoginIdentityContext();
if (obj.has(Constants.ACCESS_TOKEN)) {
loginIdentityContext
.setParameter(NacosAuthLoginConstant.ACCESSTOKEN, obj.get(Constants.ACCESS_TOKEN).asText());
loginIdentityContext.setParameter(NacosAuthLoginConstant.TOKENTTL, obj.get(Constants.TOKEN_TTL).asText());
} else {
SECURITY_LOGGER.info("[NacosClientAuthServiceImpl] ACCESS_TOKEN is empty from response");
}
return loginIdentityContext;
} catch (Exception e) {
SECURITY_LOGGER.error("[NacosClientAuthServiceImpl] login http request failed"
+ " url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, bodyMap, e.getMessage());
return null;
}
}
}
于是查看当前 JacksonUtils 是哪个包中的!本人用的 2.15.2 有问题,2.15.2 之前的版本应该都有该问题。故开始变更jackson-databind 版本, 更换完成后发现服务正常注册。
解决方案:
更换 nacos 中的 jackson-databind 版本
<dependency>
<artifactId>nacos-client</artifactId>
<groupId>com.alibaba.nacos</groupId>
<exclusions>
<exclusion>
<artifactId>jackson-databind</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>
注意:变更 pom 后刷新maven, 用 maven helper 或者mvn tree 看看对应的版本是否已经被变更。
再次启动成功注册,问题解决