赞
踩
配置中心中的配置往往存在需要加密的配置,比如数据库用户名、密码等。由于项目中同时使用nacos&apollo,所以需要实现一下两种配置中心的自动化解密
以jaspyt作为解密框架,这里jaspyt没有使用starter的原因是可能各项目springboot版本不同,可能存在兼容性问题。如果是新项目可以考虑使用统一版本的starter实现自动化解密
- <dependency>
- <groupId>org.jasypt</groupId>
- <artifactId>jasypt</artifactId>
- <version>1.9.3</version>
- </dependency>
从网上找一个简单的工具类:
- /**
- * 需解密的标记头
- */
- private static final String ENCRYPTED_VALUE_PREFIX = "ENC(";
-
- /**
- * 需解密的标记尾
- */
- private static final String ENCRYPTED_VALUE_SUFFIX = ")";
-
- /**
- * 解密密码
- */
- public static final String JASYPT_PASSWORD = "xxx";
-
-
- /**
- * 判断是否是 prefixes/suffixes 包裹的属性
- *
- * @param value
- * @return
- */
- public static boolean isEncryptedValue(final String value) {
- if (value == null) {
- return false;
- }
- final String trimmedValue = value.trim();
- return (trimmedValue.startsWith(ENCRYPTED_VALUE_PREFIX) &&
- trimmedValue.endsWith(ENCRYPTED_VALUE_SUFFIX));
- }
-
- /**
- * 如果通过 prefixes/suffixes 包裹的属性,那么返回密文的值;如果没有被包裹,返回原生的值。
- *
- * @param value
- * @return
- */
- private static String getInnerEncryptedValue(final String value) {
- return value.substring(
- ENCRYPTED_VALUE_PREFIX.length(),
- (value.length() - ENCRYPTED_VALUE_SUFFIX.length()));
- }
-
-
- /**
- * Jasypt生成加密结果
- *
- * @param password 配置文件中设定的加密密码 jasypt.encryptor.password
- * @param value 待加密值
- * @return
- */
- public static String encryptPwd(String password, String value) {
- PooledPBEStringEncryptor encryptOr = new PooledPBEStringEncryptor();
- encryptOr.setConfig(cryptOr(password));
- return encryptOr.encrypt(value);
- }
-
- /**
- * 解密
- *
- * @param password 配置文件中设定的加密密码 jasypt.encryptor.password
- * @param value 待解密密文
- * @return
- */
- public static String decyptPwd(String password, String value) {
- PooledPBEStringEncryptor encryptOr = new PooledPBEStringEncryptor();
- encryptOr.setConfig(cryptOr(password));
- return encryptOr.decrypt(isEncryptedValue(value) ? getInnerEncryptedValue(value) : value);
- }
-
- /**
- * @param password salt
- * @return
- */
- public static SimpleStringPBEConfig cryptOr(String password) {
- SimpleStringPBEConfig config = new SimpleStringPBEConfig();
- config.setPassword(password);
- config.setAlgorithm(StandardPBEByteEncryptor.DEFAULT_ALGORITHM);
- config.setKeyObtentionIterations("1000");
- config.setPoolSize("1");
- config.setProviderName(null);
- config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
- config.setStringOutputType("base64");
- return config;
- }
使用了apollo的1.3的客户端:
- <dependency>
- <groupId>com.ctrip.framework.apollo</groupId>
- <artifactId>apollo-client</artifactId>
- <version>1.3.0</version>
- </dependency>
经过断点调试,发现apollo更新配置时都会经过这个方法:
修改如下,使用了jaspyt包中的加解密方法,实现了配置在同步后的自动化解密:
- Set<Object> keys = newConfigProperties.keySet();
- for (Object k : keys) {
- String key = k.toString();
- String value = newConfigProperties.getProperty(key);
- //判断是否是规则密文
- if (JasyptUtils.isEncryptedValue(value)) {
- try {
- // 解密然后重新赋值
- String decyptVal = JasyptUtils.decyptPwd(JasyptUtils.JASYPT_PASSWORD, value);
- newConfigProperties.setProperty(key, decyptVal);
- } catch (Exception e) {
- logger.error("错误信息是:{}, 错误堆栈是:{}", ExceptionUtil.getMessage(e),
- ExceptionUtil.stacktraceToString(e));
- }
- }
- }
需要替换下面的模块实现配置自动解密:
新建一个相同的类,覆盖掉这个工厂类即可。最后通过apollo提供的spi接口com.ctrip.framework.apollo.internals.Injector替换掉这个模块装配器
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
- <version>2021.1</version>
- </dependency>
经过断点调试,发现nacos同步配置时都会经过这个方法:
该类是在这个配置器中自动装配的:
经过分析源码得知,这个配置器是通过springcloud上下文启动的,并且没有加@ConditionalOnMissingBean注解,在spring上下文中替换比较麻烦。所以最简便的方法是增加一个同名包和同名bean:
修改方法loadNacosDataIfPresent:
- private void loadNacosDataIfPresent(final CompositePropertySource composite,
- final String dataId, final String group, String fileExtension,
- boolean isRefreshable) {
- if (null == dataId || dataId.trim().length() < 1) {
- return;
- }
- if (null == group || group.trim().length() < 1) {
- return;
- }
- NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group, fileExtension, isRefreshable);
- Map<String, Object> source = propertySource.getSource();
- for (String key : source.keySet()) {
- String value = source.get(key).toString();
- if (JasyptUtils.isEncryptedValue(value)) {
- try {
- String decryptValue = JasyptUtils.decyptPwd(JasyptUtils.JASYPT_PASSWORD, value);
- source.put(key, decryptValue);
- } catch (Exception e) {
- log.error("nacos解密失败!请检察是否包含正确的密文:错误信息是:{}, 错误堆栈是:{}", ExceptionUtil.getMessage(e),
- ExceptionUtil.stacktraceToString(e));
- }
- }
-
- }
- this.addFirstPropertySource(composite, propertySource, false);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。