扩展Nacos使其支持https和登陆 拉取配置 com.alibaba.nacos.client.naming.tls.enable
官方依赖版本:
nacos-server :1.2.1 nacos-config-spring-boot.version :0.2.7
nacos server支持启用鉴权 ### If turn on auth system: nacos.core.auth.enabled=true
按照官方example( https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-config-example )配置好 发现客户端连接不上,总是403的错误,根据惯例来讲,这是没有授权引起的,然后我去github上找了下,果然有人提了这个 issue

问题有了,那么接下来追踪产生的原因。
跟踪源码发现 login 方法调用HttpClient 而 nacos server的数据接口是用ServerHttpAgent->HttpSimpleClient ,都是对HttpConnection的包装,但内部url拼接规则不同

由于这里拼接了“/”,导致 nacos上下文配置拼接时路径变成了//
nacos.config.context-path=/nacosnacos server端使用了spring security进行权限,在新版的spring security中,对url进行了规则强校验,不允许类似“http://127.0.0.1//xxx”这种"//“出现,导致出现获取配置出现500的错误。(如果设置nacos.config.context-path=nacos 又会导致登陆失败,拿不到accessToken)
所以如果要不该源码实现 登陆权限 拉取配置需要 通过代理转换请求地址。
于是在nacos server端配置nginx 代理请求

在访问nacos前加入一层nginx
location / {
proxy_pass http://127.0.0.1:8848/;
}
location /n/nacos {
proxy_pass http://127.0.0.1:8848/nacos/;
}
这样做的目的是为了重写”//“为”/",保证security的url校验能够成功,
其中 nacosserver是nacos的访问url,这里我配置了两个,第一个是访问nacos的管理界面,第二个是client注册nacos的url
这样登陆授权是满足了,http明文传输配置中心的密码等敏感信息还是不够安全,所以扩展nacos使其支持https就是问题了
由于ServerHttpAgent类源码写死了 isSSL=false,看来不该源码不行了。(本来想替换ClientWorker的agent实例,结果发现是
NacosConfigService New出来的,和Spring框架设计上的差距有点大啊————)
好吧,源码开撸>>>>
修改ServerHttpAgent
private String getUrl(String serverAddr, String relativePath,boolean isSSL) {
String contextPath = serverListMgr.getContentPath().startsWith("/") ?
serverListMgr.getContentPath() : "/" + serverListMgr.getContentPath();
String url= StringUtils.removeEnd(serverAddr,"/")+"/"+StringUtils.removeStart(contextPath,"/")+ relativePath;
if (isSSL &&url.startsWith(httpPre)){
return httpsPre+StringUtils.removeStart(url,httpPre);
}else{
return url;
}
}SecurityProxy.java
if (HttpClient.ENABLE_HTTPS){
url = "https://" + server + contextPath + LOGIN_URL;
}else {
url = "http://" + server + contextPath + LOGIN_URL;
}
if (server.contains(Constants.HTTP_PREFIX)||server.contains(Constants.HTTPS_PREFIX)) {
url = server + contextPath + LOGIN_URL;
}为了避免证书 校验 请求域名的问题 对HttpConnection所在类做了以下处理
static {
try {
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier
(
(urlHostName, session) -> true
);
} catch (Exception e) {
}
}
private static void trustAllHttpsCertificates()
throws NoSuchAlgorithmException, KeyManagementException {
TrustManager[] trustAllCerts = new TrustManager[1];
trustAllCerts[0] = new TrustAllManager();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(
sc.getSocketFactory());
}
private static class TrustAllManager
implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
}为了避免配置过于杂乱,对于是否启用ssl依然复用 这个属性
com.alibaba.nacos.client.naming.tls.enable
启动类加System.setProperty("com.alibaba.nacos.client.naming.tls.enable","true")或者 启动命令加-Dcom.alibaba.nacos.client.naming.tls.enable
完整代码参见我的github https://github.com/huawenyao/nacos ,欢迎start~
关键源码
ServerHttpAgent.httpGet
private String getUrl(String serverAddr, String relativePath) {
return serverAddr + "/" + serverListMgr.getContentPath() + relativePath;
}
public NacosConfigService(Properties properties) throws NacosException {
String encodeTmp = properties.getProperty(PropertyKeyConst.ENCODE);
if (StringUtils.isBlank(encodeTmp)) {
encode = Constants.ENCODE;
} else {
encode = encodeTmp.trim();
}
initNamespace(properties);
agent = new MetricsHttpAgent(new ServerHttpAgent(properties));
agent.start();
worker = new ClientWorker(agent, configFilterChainManager, properties);
}
推荐:vi设计公司