(一) Springboot配置文件加解密插件jasypt解密过程源码分析

1 对配置文件的解密

1.1 解密主体流程:

  • 1 先在启动的时候注入一个PostProcessor
  • 2 在PostProcessor中进行将普通的PropertySource转换成EncryptPropertySource
  • 3 在EncryptPropertySource getProperty的时候 其中代理了PropertySource,进行获取源加密属性值,解密返回

2 将普通的PropertySource转换成EncryptPropertySource 加密属性资源类

2.1 转换EncryptPropertySource的步骤总结

  • PostProcessor中获取MutablePropertySource
  • 对MutablePropertySource中非EncryptPropertySource进行转换替换

2.2 转换EncryptPropertySource的 源码分析

  • 在jaspcry-spring-boot-starter的jar包中找到自动装配的入口:spring.factories

image.png

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ulisesbocchio.jasyptspringboot.JasyptSpringBootAutoConfiguration

  • 入口自动装配类 JasyptSpringBootAutoConfiguration

    • Import 注册进来的配置类 EnableEncryptablePropertiesConfiguration
    @Configuration
    @Import({EnableEncryptablePropertiesConfiguration.class})
    public class JasyptSpringBootAutoConfiguration {
        public JasyptSpringBootAutoConfiguration() {
        }
    }
    
  • EnableEncryptablePropertiesConfiguration配置类中做了三个操作

    • 引入两个配置类EncryptablePropertyResolverConfiguration和CachingConfiguration
    • 注册了一个开启加密的Bean工厂后置处理EnableEncryptablePropertiesBeanFactoryPostProcessor
    @Configuration
    @Import({EncryptablePropertyResolverConfiguration.class, CachingConfiguration.class})
    @Slf4j
    public class EnableEncryptablePropertiesConfiguration {
    
        @Bean
        public static EnableEncryptablePropertiesBeanFactoryPostProcessor enableEncryptablePropertySourcesPostProcessor(final ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
            return new EnableEncryptablePropertiesBeanFactoryPostProcessor(environment, converter);
        }
    }
    
    
  • 主要操作流程在EnableEncryptablePropertiesBeanFactoryPostProcessor中处理

    • EncryptablePropertySourceConverter.convertPropertySources(propSources)转换包装类型
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            LOG.info("Post-processing PropertySource instances");
    		// 从environment中获取要处理的资源配置MutablePropertySources 
            MutablePropertySources propSources = environment.getPropertySources();
            // 将MutablePropertySources 中的所有的资源配置转换成加密PropertySource
            converter.convertPropertySources(propSources);
        }
    
  • EncryptablePropertySourceConverter

    • filter(ps -> !(ps instanceof EncryptablePropertySource)) 过滤获取非EncryptablePropertySource的PropertySources

    • 将所有的非EncryptablePropertySource的PropertySource转换成EncryptablePropertySource

    • 将转换之后的EncryptablePropertySource替换到MutablePropertySources中

    • 处理完之后MutablePropertySources中全部都是EncryptablePropertySource(

      EncryptableSystemEnvironmentPropertySourceWrapper,EncryptableMapPropertySourceWrapper,EncryptableEnumerablePropertySourceWrapper,EncryptablePropertySourceWrapper
      

      )

    public void convertPropertySources(MutablePropertySources propSources) {
        StreamSupport.stream(propSources.spliterator(), false)
                .filter(ps -> !(ps instanceof EncryptablePropertySource))
                .map(this::makeEncryptable)
                .collect(toList())
                .forEach(ps -> propSources.replace(ps.getName(), ps));
    }

转换EncryptablePropertySource实现类(EncryptableSystemEnvironmentPropertySourceWrapper,EncryptableMapPropertySourceWrapper,EncryptableEnumerablePropertySourceWrapper,EncryptablePropertySourceWrapper)的源码

    public <T> PropertySource<T> makeEncryptable(PropertySource<T> propertySource) {
        if (propertySource instanceof EncryptablePropertySource || skipPropertySourceClasses.stream().anyMatch(skipClass -> skipClass.equals(propertySource.getClass()))) {
            log.info("Skipping PropertySource {} [{}", propertySource.getName(), propertySource.getClass());
            return propertySource;
        }
        // 进行转换EncryptablePropertySource
        PropertySource<T> encryptablePropertySource = convertPropertySource(propertySource);
        log.info("Converting PropertySource {} [{}] to {}", propertySource.getName(), propertySource.getClass().getName(),
                AopUtils.isAopProxy(encryptablePropertySource) ? "AOP Proxy" : encryptablePropertySource.getClass().getSimpleName());
        return encryptablePropertySource;
    }

进行实际转换的源码:

    private <T> PropertySource<T> instantiatePropertySource(PropertySource<T> propertySource) {
        PropertySource<T> encryptablePropertySource;
        if (needsProxyAnyway(propertySource)) {
            encryptablePropertySource = proxyPropertySource(propertySource);
        } else if (propertySource instanceof  SystemEnvironmentPropertySource) {
            encryptablePropertySource = (PropertySource<T>) new EncryptableSystemEnvironmentPropertySourceWrapper((SystemEnvironmentPropertySource) propertySource, propertyResolver, propertyFilter);
        } else if (propertySource instanceof MapPropertySource) {
            encryptablePropertySource = (PropertySource<T>) new EncryptableMapPropertySourceWrapper((MapPropertySource) propertySource, propertyResolver, propertyFilter);
        } else if (propertySource instanceof EnumerablePropertySource) {
            encryptablePropertySource = new EncryptableEnumerablePropertySourceWrapper<>((EnumerablePropertySource) propertySource, propertyResolver, propertyFilter);
        } else {
            encryptablePropertySource = new EncryptablePropertySourceWrapper<>(propertySource, propertyResolver, propertyFilter);
        }
        return encryptablePropertySource;
    }

在该处将所有的PropertySource都转换成了EncryptablePropertySource

3 解密配置文件依赖的EncryptPropertySource的加密实现类中的getProperty

3.1 解密流程

  • 从Eviroment中获取属性值,依赖于EncryptPropertySource的getProperty
    每个EncryptPropertySource实现类中都代理了CachingDelegateEncryptablePropertySource
  • CachingDelegateEncryptablePropertySource中代理了PropertySource
  • CachingDelegateEncryptablePropertySource.getProperty 实现从PropertySource中获取加密密文,解密密文,返回解密值得解密流程

3.2 解密源码

挑选其中一个实现类EncryptableSystemEnvironmentPropertySourceWrapper,其他的实现类实现都一样

  • EncryptableSystemEnvironmentPropertySourceWrapper

    • 构造方法中代理CachingDelegateEncryptablePropertySource
public class EncryptableSystemEnvironmentPropertySourceWrapper extends SystemEnvironmentPropertySource implements EncryptablePropertySource<Map<String, Object>> {

    private final EncryptablePropertySource<Map<String, Object>> encryptableDelegate;
    //1 注入了CachingDelegateEncryptablePropertySource代理类
    public EncryptableSystemEnvironmentPropertySourceWrapper(SystemEnvironmentPropertySource delegate, EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter) {
        super(delegate.getName(), delegate.getSource());
        encryptableDelegate = new CachingDelegateEncryptablePropertySource<>(delegate, resolver, filter);
    }

    @Override
    public void refresh() {
        encryptableDelegate.refresh();
    }
    //2 从代理的CachingDelegateEncryptablePropertySource中获取属性值
    @Override
    public Object getProperty(String name) {
        return encryptableDelegate.getProperty(name);
    }

    @Override
    public PropertySource<Map<String, Object>> getDelegate() {
        return encryptableDelegate.getDelegate();
    }
}
  • CachingDelegateEncryptablePropertySource
    • 注入PropertySource代理类
    • getProperty 获取PropertySource中密文进行解密

public class CachingDelegateEncryptablePropertySource<T> extends PropertySource<T> implements EncryptablePropertySource<T> {
    private final PropertySource<T> delegate;
    private final EncryptablePropertyResolver resolver;
    private final EncryptablePropertyFilter filter;
    private final Map<String, Object> cache;

    public CachingDelegateEncryptablePropertySource(PropertySource<T> delegate, EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter) {
        super(delegate.getName(), delegate.getSource());
        Assert.notNull(delegate, "PropertySource delegate cannot be null");
        Assert.notNull(resolver, "EncryptablePropertyResolver cannot be null");
        Assert.notNull(filter, "EncryptablePropertyFilter cannot be null");
        this.delegate = delegate;
        this.resolver = resolver;
        this.filter = filter;
        this.cache = new HashMap<>();
    }

    @Override
    public PropertySource<T> getDelegate() {
        return delegate;
    }
   // 该处将获取属性进行了一步缓存,防止重复获取和解密
    @Override
    public Object getProperty(String name) {
        // Can be called recursively, so, we cannot use computeIfAbsent.
        if (cache.containsKey(name)) {
            return cache.get(name);
        }
        synchronized (this) {
            if (!cache.containsKey(name)) {
               // 获取明文
                Object resolved = getProperty(resolver, filter, delegate, name);
                if (resolved != null) {
                    cache.put(name, resolved);
                }
            }
            return cache.get(name);
        }
    }

    @Override
    public void refresh() {
        cache.clear();
    }
}

public interface EncryptablePropertySource<T> {

    PropertySource<T> getDelegate();

    Object getProperty(String name);

    void refresh();

    default Object getProperty(EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter, PropertySource<T> source, String name) {
        Object value = source.getProperty(name);
        if (filter.shouldInclude(source, name) && value instanceof String) {
            String stringValue = String.valueOf(value);
            // 进行解密
            return resolver.resolvePropertyValue(stringValue);
        }
        return value;
    }
}

DefaultPropertyResolver 进行实际解密的位置

    @Override
    public String resolvePropertyValue(String value) {
        return Optional.ofNullable(value)
                .map(environment::resolvePlaceholders)
                .filter(detector::isEncrypted)
                .map(resolvedValue -> {
                    try {
  
                        String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim());
                        String resolvedProperty = environment.resolvePlaceholders(unwrappedProperty);
						//进行解密  
						return encryptor.decrypt(resolvedProperty);
                    } catch (EncryptionOperationNotPossibleException e) {
                        throw new DecryptionException("Unable to decrypt: " + value + ". Decryption of Properties failed,  make sure encryption/decryption " +
                                "passwords match", e);
                    }
                })
                .orElse(value);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值