官方依赖版本:
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);
}