apache / dubbo

The java implementation of Apache Dubbo. An RPC and microservice framework.
https://dubbo.apache.org/
Apache License 2.0
40.45k stars 26.42k forks source link

dubbo2.7.6注册nacos-1.2.1配置用户名密码配置不生效 #6723

Closed nickszeng closed 3 years ago

nickszeng commented 4 years ago

Environment

Steps to reproduce this issue

maven依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

-- dubbo版本:2.7.6 -- nacos版本:1.2.1 dubbo配置Nacos报无权限错误

com.alibaba.nacos.api.exception.NacosException: failed to req API:/api//nacos/v1/ns/instance after all servers([17.128.1.16:8848]) tried:
 <html><body><h1>Whitelabel Error Page</h1>
 <p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
 <div id='created'>Fri Sep 11 14:48:51 CST 2020</div>
 <div>There was an unexpected error (type=Forbidden, status=403).</div>
 <div>unknown user!</div></body></html>
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:496)
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:401)
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:397)

初步以为是未配置注册中心用户名密码 -- 尝试添加如下配置:结果还是一样报错

dubbo:
  registry:
    parameters:
      username: nacos
      password: nacos

于是跟踪了下注册流程 1.dubbo通过配置 nacos:// 找到对应注册工厂

public class NacosRegistryFactory extends AbstractRegistryFactory {
    ...
    @Override
    protected Registry createRegistry(URL url) {
        return new NacosRegistry(url, NacosNamingServiceUtils.createNamingService(url));
    }
}

可以看出dubbo是通过url参数来初始化Nacos的NamingService DEBUG现场可以看到 用户名密码信息是存在的

url参数

2.创建Nacos NamingService服务 org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils#createNamingService

public static NamingService createNamingService(URL connectionURL) {
    //从URL解析为properties对象
    Properties nacosProperties = buildNacosProperties(connectionURL);
    NamingService namingService;
    try {
        namingService = NacosFactory.createNamingService(nacosProperties);
    } catch (NacosException e) {
        if (logger.isErrorEnabled()) {
            logger.error(e.getErrMsg(), e);
        }
        throw new IllegalStateException(e);
    }
    return namingService;
}

3.从URL解析为Properties对象

org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils#buildNacosProperties
private static Properties buildNacosProperties(URL url) {
    Properties properties = new Properties();
    setServerAddr(url, properties);
    setProperties(url, properties);
    return properties;
}

org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils#setServerAddr|setProperties

private static void setServerAddr(URL url, Properties properties) {
    StringBuilder serverAddrBuilder =
            new StringBuilder(url.getHost()) // Host
                    .append(":")
                    .append(url.getPort()); // Port

    // Append backup parameter as other servers
    String backup = url.getParameter(BACKUP_KEY);
    if (backup != null) {
        serverAddrBuilder.append(",").append(backup);
    }

    String serverAddr = serverAddrBuilder.toString();
    properties.put(SERVER_ADDR, serverAddr);
}
private static void setProperties(URL url, Properties properties) {
    putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME);
    putPropertyIfAbsent(url, properties, IS_USE_CLOUD_NAMESPACE_PARSING);
    putPropertyIfAbsent(url, properties, IS_USE_ENDPOINT_PARSING_RULE);
    putPropertyIfAbsent(url, properties, ENDPOINT);
    putPropertyIfAbsent(url, properties, ENDPOINT_PORT);
    putPropertyIfAbsent(url, properties, NAMESPACE);
    putPropertyIfAbsent(url, properties, ACCESS_KEY);
    putPropertyIfAbsent(url, properties, SECRET_KEY);
    putPropertyIfAbsent(url, properties, RAM_ROLE_NAME);
    putPropertyIfAbsent(url, properties, CONTEXT_PATH);
    putPropertyIfAbsent(url, properties, CLUSTER_NAME);
    putPropertyIfAbsent(url, properties, ENCODE);
    putPropertyIfAbsent(url, properties, CONFIG_LONG_POLL_TIMEOUT);
    putPropertyIfAbsent(url, properties, CONFIG_RETRY_TIME);
    putPropertyIfAbsent(url, properties, MAX_RETRY);
    putPropertyIfAbsent(url, properties, ENABLE_REMOTE_SYNC_CONFIG);
    putPropertyIfAbsent(url, properties, NAMING_LOAD_CACHE_AT_START, "true");
    putPropertyIfAbsent(url, properties, NAMING_CLIENT_BEAT_THREAD_COUNT);
    putPropertyIfAbsent(url, properties, NAMING_POLLING_THREAD_COUNT);
}

com.alibaba.nacos.api.NacosFactory#createNamingService(java.util.Properties)

public static NamingService createNamingService(Properties properties) throws NacosException {
    return NamingFactory.createNamingService(properties);
}

com.alibaba.nacos.client.naming.NacosNamingService#NacosNamingService

public NacosNamingService(Properties properties) {
    init(properties);
}

private void init(Properties properties) {
    namespace = InitUtils.initNamespaceForNaming(properties);
    initServerAddr(properties);
    InitUtils.initWebRootContext();
    initCacheDir();
    initLogName(properties);
    eventDispatcher = new EventDispatcher();
    serverProxy = new NamingProxy(namespace, endpoint, serverList, properties);
     ...
}

4.实例化NamingProxy及SecurityProxy对象

public NamingProxy(String namespaceId, String endpoint, String serverList, Properties properties) {
    //初始化安全代理对象
    securityProxy = new SecurityProxy(properties);
    ...
}

public SecurityProxy(Properties properties) {
    username = properties.getProperty(PropertyKeyConst.USERNAME, StringUtils.EMPTY);
    password = properties.getProperty(PropertyKeyConst.PASSWORD, StringUtils.EMPTY);
    ...
}

DEBUG现场

properties ser

可以看到从刚开始URL中的用户名密码到后面并未传递到Nacos注册中心。

临时解决方案

1.添加自定义注册中心工厂

1.参考org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils
2.添加自定义CustomNacosNamingServiceUtils
3.添加用户名密码参数映射 (其他方法不动)
private static void setProperties(URL url, Properties properties) {
    //添加用户名密码映射
     if (StringUtils.isNotEmpty(url.getUsername())) {
        properties.setProperty(USERNAME, url.getUsername());
    }
    if (StringUtils.isNotEmpty(url.getPassword())) {
        properties.setProperty(PASSWORD, url.getPassword());
    }
    putPropertyIfAbsent(url, properties, USERNAME);
    putPropertyIfAbsent(url, properties, PASSWORD);
    ...
}

2.按如下配置

1.自定义SPI配置文件
resources
--META-INF
    --dubbo
        --internal
            --org.apache.dubbo.registry.RegistryFactory 

2.添加如下内容
nacos-security=com.xxx.registry.NacosSecurityRegistryFactory

3.修改配置中心
dubbo:
    registry:
      address: 'nacos-security://${nacos.address}'

再次启动不在报错

Actual Result

1599810937
nickszeng commented 4 years ago

解决办法二:修改为spring-cloud方式的注册中心 dubbo.registry.address='spring-cloud://localhost' ,此通过spring cloud的discovery client(找到NacosDiscoveryClient)获取实例

ppzzyy11 commented 4 years ago

mark

wuguocai commented 3 years ago

解决办法二:修改为spring-cloud方式的注册中心 dubbo.registry.address='spring-cloud://localhost' ,此通过spring cloud的discovery client(找到NacosDiscoveryClient)获取实例

但是这样元数据中看不到具体的接口注册信息,有办法解决吗

AlbumenJ commented 3 years ago

This issue may be related with #7172

zhangpeibisha commented 2 years ago

https://nacos.io/zh-cn/docs/open-api.html 我发现根本就没有输入账号密码的参数,真的有人配置成功的吗?

persevere1 commented 2 years ago

可以通过将用户名和密码配置在地址参数后(我使用的是dubbo版本是2.7.13):

dubbo.registries.nacos.address=nacos://my.nacos:8848?username=nacos&password=nacos

wangsenyan commented 2 years ago

标记下,我使用了版本2.7.13,按上面的可以

steveGuRen commented 2 years ago
  <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
    <version>2.2.6.RELEASE</version>
  </dependency>

通过这个引入的dubbo2.7.8版本也是可以类似dubbo.registries.nacos.address=nacos://my.nacos:8848?username=nacos&password=nacos处理

auroraslot commented 1 year ago

官方文档好像没写这个,我的dubbo版本是2.7.7,nacos服务端是2.2.3,客户端是2.0.3

在org.apache.dubbo.config.ConfigCenterConfig#setAddress这个位置发现username和password是在这里赋值,逻辑是从dubbo.registry.address里面拿到

原URL:nacos://[nacos_server_ip]:8848?namespace=dev

改成:nacos://[username]:[password]@[nacos_server_ip]:8848?namespace=dev

具体到解析规则在这里:org.apache.dubbo.common.URL#valueOf(java.lang.String)

mianqiangsheng commented 1 year ago

帮了大忙了,我按照楼主的方案一解决了我的问题