nacos账号加密方式参考:https://blog.youkuaiyun.com/weixin_39418319/article/details/140544019?spm=1001.2014.3001.5502
但是,引入Spring Cloud 2020之后版本后,有些项目可能因为Spring Cloud不再默认支持bootstrap配置,把bootstrap配置文件去掉了,项目中所有配置都写在了application.yaml里,那上面加密方式就会在NacosConfigDataLocationResolver这个类中由于无法解密连接报错,针对这种情况,可以用下面这种方式,重写对应nacos配置类
解决方案
在项目中创建package com.alibaba.cloud.nacos,重写的类必须和nacos中的类放在相同路径下才能覆盖nacos本身的类
重写com.alibaba.cloud.nacos.NacosConfigProperties
nacos中原来的com.alibaba.cloud.nacos.NacosConfigProperties复制过来,修改overrideFromEnv这个方法,加上解密代码,解密代码自己实现就可以,我是使用了jasypt的PropertyValueEncryptionUtils
private void overrideFromEnv() {
if (environment == null) {
return;
}
if (StringUtils.isEmpty(this.getServerAddr())) {
String serverAddr = environment
.resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}");
if (StringUtils.isEmpty(serverAddr)) {
serverAddr = environment.resolvePlaceholders(
"${spring.cloud.nacos.server-addr:127.0.0.1:8848}");
}
this.setServerAddr(serverAddr);
}
// 这里的加解密可以自己实现,我的项目是没有在nacos.config配置下加账号和密码的,所以取得都是spring.cloud.nacos.username和spring.cloud.nacos.password的值
if (StringUtils.isEmpty(this.getUsername())) {
this.setUsername(
environment.resolvePlaceholders("${spring.cloud.nacos.username:}"));
}
if (StringUtils.isEmpty(this.getPassword())) {
this.setPassword(
environment.resolvePlaceholders("${spring.cloud.nacos.password:}"));
}
// 获取加密盐值
try {
String saltStr = environment.resolveRequiredPlaceholders("${spring.cloud.nacos.salt:}");
this.setSalt(saltStr);
} catch (IllegalArgumentException e) {
log.warn("spring.cloud.nacos.salt is Illegal Argument or empty!" );
}
String saltStr = this.getSalt();
// 如果加密盐值不为空且username符合加密格式,则进行账号解密处理
if (StringUtils.isNotBlank(saltStr) && PropertyValueEncryptionUtils.isEncryptedValue(this.getUsername())) {
this.setUsername(decrypt(this.getUsername(), saltStr));
}
// 如果加密盐值不为空且password符合加密格式,则进行密码解密处理
if (StringUtils.isNotBlank(saltStr) && PropertyValueEncryptionUtils.isEncryptedValue(this.getPassword())) {
this.setPassword(decrypt(this.getPassword(), saltStr));
}
}
重写com.alibaba.cloud.nacos.configdata.NacosConfigDataLocationResolver
一样的方式复制原本类的内容,修改loadProperties方法
protected NacosConfigProperties loadProperties(
ConfigDataLocationResolverContext context) {
Binder binder = context.getBinder();
BindHandler bindHandler = getBindHandler(context);
NacosConfigProperties nacosConfigProperties;
if (context.getBootstrapContext().isRegistered(NacosConfigProperties.class)) {
nacosConfigProperties = context.getBootstrapContext()
.get(NacosConfigProperties.class);
}
else {
nacosConfigProperties = binder
.bind("spring.cloud.nacos", Bindable.of(NacosConfigProperties.class),
bindHandler)
.map(properties -> binder
.bind(NacosConfigProperties.PREFIX,
Bindable.ofInstance(properties), bindHandler)
.orElse(properties))
.orElseGet(() -> binder
.bind(NacosConfigProperties.PREFIX,
Bindable.of(NacosConfigProperties.class), bindHandler)
.orElseGet(NacosConfigProperties::new));
}
// 获取加密盐值
String salt = nacosConfigProperties.getSalt();
// 如果加密盐值不为空且username符合加密格式,则进行账号解密处理
String username = nacosConfigProperties.getUsername();
if (StringUtils.isNotBlank(salt) && StringUtils.isNotBlank(username) && PropertyValueEncryptionUtils.isEncryptedValue(username)) {
nacosConfigProperties.setUsername(NacosConfigProperties.decrypt(username, salt));
}
// 如果加密盐值不为空且password符合加密格式,则进行密码解密处理
String password = nacosConfigProperties.getPassword();
if (StringUtils.isNotBlank(salt) && StringUtils.isNotBlank(password) && PropertyValueEncryptionUtils.isEncryptedValue(password)) {
nacosConfigProperties.setPassword(NacosConfigProperties.decrypt(password, salt));
}
return nacosConfigProperties;
}
重写com.alibaba.cloud.nacos.NacosDiscoveryProperties
修改overrideFromEnv方法
public void overrideFromEnv(Environment env) {
if (StringUtils.isEmpty(this.getServerAddr())) {
String serverAddr = env
.resolvePlaceholders("${spring.cloud.nacos.discovery.server-addr:}");
if (StringUtils.isEmpty(serverAddr)) {
serverAddr = env.resolvePlaceholders(
"${spring.cloud.nacos.server-addr:127.0.0.1:8848}");
}
this.setServerAddr(serverAddr);
}
if (StringUtils.isEmpty(this.getNamespace())) {
this.setNamespace(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.namespace:}"));
}
if (StringUtils.isEmpty(this.getAccessKey())) {
this.setAccessKey(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.access-key:}"));
}
if (StringUtils.isEmpty(this.getSecretKey())) {
this.setSecretKey(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.secret-key:}"));
}
if (StringUtils.isEmpty(this.getLogName())) {
this.setLogName(
env.resolvePlaceholders("${spring.cloud.nacos.discovery.log-name:}"));
}
if (StringUtils.isEmpty(this.getClusterName())) {
this.setClusterName(env.resolvePlaceholders(
"${spring.cloud.nacos.discovery.cluster-name:}"));
}
if (StringUtils.isEmpty(this.getEndpoint())) {
this.setEndpoint(
env.resolvePlaceholders("${spring.cloud.nacos.discovery.endpoint:}"));
}
if (StringUtils.isEmpty(this.getGroup())) {
this.setGroup(
env.resolvePlaceholders("${spring.cloud.nacos.discovery.group:}"));
}
if (StringUtils.isEmpty(this.getUsername())) {
this.setUsername(env.resolvePlaceholders("${spring.cloud.nacos.username:}"));
}
if (StringUtils.isEmpty(this.getPassword())) {
this.setPassword(env.resolvePlaceholders("${spring.cloud.nacos.password:}"));
}
// 获取账号加密的盐值
String salt = StringUtils.EMPTY;
try {
salt = environment.resolveRequiredPlaceholders("${spring.cloud.nacos.salt:}");
} catch (IllegalArgumentException e) {
log.warn("spring.cloud.nacos.salt is Illegal Argument or empty!" );
}
// 如果加密盐值不为空且username符合加密格式,则进行账号解密处理
if (StringUtils.isNotBlank(salt) && StringUtils.isNotBlank(this.getUsername()) && PropertyValueEncryptionUtils.isEncryptedValue(this.getUsername())) {
this.setUsername(decrypt(this.getUsername(), salt));
}
// 如果加密盐值不为空且password符合加密格式,则进行密码解密处理
if (StringUtils.isNotBlank(salt) && StringUtils.isNotBlank(this.getPassword()) && PropertyValueEncryptionUtils.isEncryptedValue(this.getPassword())) {
this.setPassword(decrypt(this.getPassword(), salt));
}
}
application.yaml中配置
spring:
main:
allow-circular-references: true
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
config:
activate:
on-profile: dev
cloud:
nacos:
server-addr: ****
# nacos账号加密
# ENC是因为延用了jasypt里PropertyValueEncryptionUtils的方法,ENC()中间的才是加密后的账号和密码
username: ENC(*****)
password: ENC(*****)
# 自己定义的加密盐值
salt: *****
说明
1、之前试过重新注入NacosConfigProperties bean,来加解密代码的方式,一直解决不了,因为NacosConfigDataLocationResolver的bean优先级最高,总是最先加载,所以目前想到的方式只有重写NacosConfigDataLocationResolver;
2、如果nacos账号有两个位置配置
spring.cloud.nacos.config.username
spring.cloud.nacos.config.password
和
spring.cloud.nacos.username
spring.cloud.nacos.password
这两个位置有优先级,注意区分
3、重写上面三个类是因为发现项目启动时这三个类都读取了账号并连接nacos,读取配置顺序是NacosConfigDataLocationResolver(读取spring.cloud.nacos.config配置)、NacosConfigProperties(读取spring.cloud.nacos下配置)、NacosDiscoveryProperties(服务发现)
参考链接
https://blog.youkuaiyun.com/weixin_39418319/article/details/140544019?spm=1001.2014.3001.5502