zoukankan      html  css  js  c++  java
  • SpringBoot:整合jasypt

    整合SpringBoot

    官方文档:https://github.com/ulisesbocchio/jasypt-spring-boot

    据官方文档介绍有三种方式可以引入jasypt

    第一种

    直接引入jasypt的starter

    <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.3</version>
    </dependency>
    

    第二种

    引入

    <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot</artifactId>
            <version>3.0.3</version>
    </dependency>
    

    然后添加@EnableEncryptableProperties在你的配置类上

    第三种

    引入

    dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot</artifactId>
            <version>3.0.3</version>
    </dependency>
    

    然后在配置类上配置如下:

    @Configuration
    @EncryptablePropertySource(name = "EncryptedProperties", value = "classpath:encrypted.properties")
    public class MyApplication {
    }
    

    同时支持多个@EncryptablePropertySource注解,如下:

    @Configuration
    @EncryptablePropertySources({@EncryptablePropertySource("classpath:encrypted.properties"),
                                 @EncryptablePropertySource("classpath:encrypted2.properties")})
    public class MyApplication {
    
    }
    

    1.8以后,配置文件支持yaml格式。

    自定义环境

    我们可以这样配置自己的环境。此方法对于早期访问springboot引导的加密属性的非常有用。

    new SpringApplicationBuilder()
        .environment(new StandardEncryptableServletEnvironment())
        .sources(YourApplicationClass.class).run(args);
    

    此外,我们可以配置StandardEncryptableServletEnvironment

    StandardEncryptableServletEnvironment env = StandardEncryptableServletEnvironment
        .builder()
        .encryptor(new StandardPBEStringEncryptor())
        .build();
    
    new SpringApplicationBuilder()
        .environment(env)
        .sources(BootJasyptApplication.class).run(args);
    

    基于密码的加密配置

    所有的配置项都在JasyptEncryptorConfigurationProperties类属性中,我们直需要在yml中配置属性,就可以达到重写的目的。

    Jasypt使用StringEncryptor来解密属性。对于上述所有3个配置方法,如果在Spring上下文中找不到自定义StringEncryptor(有关详细信息,请参阅自定义Encryptor部分),则会自动创建一个,可以通过以下属性(系统、属性文件、命令行参数、环境变量等)进行配置:

    image-20210507101847493

    唯一需要的属性是加密密码,其余的可以使用默认值。虽然所有这些属性都可以在属性文件中声明,但加密程序密码不应该存储在属性文件中,而应该作为系统属性、命令行参数或环境变量传递,只要它的名称是jasypt.encryptor.password,它就可以工作。

    最后一个属性jasypt.encryptor.proxyPropertySources用于指示jasyp spring boot如何拦截属性值进行解密。默认值false使用PropertySource、EnumerablePropertySource和MapPropertySource的自定义包装器实现。当为此属性指定true时,拦截机制将在每个特定的PropertySource实现上使用CGLib代理。在某些必须保留原始PropertySource类型的场景中,这可能很有用。

    自定义加密

    默认情况下,bean容器会配置LazyJasyptStringEncryptor

    对于加密程序和加密程序密码源的自定义配置,您始终可以在Spring上下文中定义自己的StringEncryptor bean,默认的加密程序将被忽略

      @Bean("jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("password");
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        return encryptor;
    }
    

    注意,bean名称是必需的,因为jasypt-spring-boot从版本1.5开始按名称检测自定义字符串jasyptStringEncryptor

    自定义属性探测器、前缀、后缀和/或解析器

    从jasypt-spring-boot-1.10开始,有新的可扩展点。EncryptablePropertySource现在使用EncryptablePropertyResolver解析所有属性

    public interface EncryptablePropertyResolver {
        String resolvePropertyValue(String value);
    }
    

    这个接口的实现负责检测和解密属性。默认实现DefaultPropertyResolver使用前面提到的StringEncryptor和新的EncryptablePropertyDetector

    自定义属性探测器

    您可以通过提供一个名为EncryptablePropertyDetector的EncryptablePropertyDetector类型的Bean来覆盖默认实现,或者如果您想提供自己的Bean名称,请覆盖属性jasypt.encryptor.property.detector-Bean并指定您想给Bean的名称。当提供这个时,您将负责检测加密属性。例子:

        @Bean(name = "encryptablePropertyDetector")
        public EncryptablePropertyDetector encryptablePropertyDetector() {
            return new MyEncryptablePropertyDetector();
        }
    
        private static class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {
            @Override
            public boolean isEncrypted(String value) {
                if (value != null) {
                    return value.startsWith("ENC@");
                }
                return false;
            }
    
            @Override
            public String unwrapEncryptedValue(String value) {
                return value.substring("ENC@".length());
            }
        }
    

    提供自定义的加密属性前缀和后缀

    如果您只想为加密属性设置不同的前缀/后缀,则可以继续使用所有默认实现,只需覆盖application.properties(或application.yml)中的以下属性

    jasypt:
      encryptor:
        property:
          prefix: "ENC@["
          suffix: "]"
    

    提供自定义EncryptablePropertyResolver

    您可以通过提供一个名为encryptablePropertyResolver的EncryptablePropertyResolver类型的Bean来覆盖默认实现,或者如果您想提供自己的Bean名称,请覆盖属性jasypt.encryptor.property.resolver-Bean并指定您想给Bean的名称。当提供这个时,您将负责检测和解密加密的属性。例子

    class MyEncryptablePropertyResolver implements EncryptablePropertyResolver {
    
    
        private final PooledPBEStringEncryptor encryptor;
    
        public MyEncryptablePropertyResolver(char[] password) {
            this.encryptor = new PooledPBEStringEncryptor();
            SimpleStringPBEConfig config = new SimpleStringPBEConfig();
            config.setPasswordCharArray(password);
            config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
            config.setKeyObtentionIterations("1000");
            config.setPoolSize(1);
            config.setProviderName("SunJCE");
            config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
            config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
            config.setStringOutputType("base64");
            encryptor.setConfig(config);
        }
    
        @Override
        public String resolvePropertyValue(String value) {
            if (value != null && value.startsWith("{cipher}")) {
                return encryptor.decrypt(value.substring("{cipher}".length()));
            }
            return value;
        }
    }
    
    @Bean(name="encryptablePropertyResolver")
    EncryptablePropertyResolver encryptablePropertyResolver(@Value("${jasypt.encryptor.password}") String password) {
        return new MyEncryptablePropertyResolver(password.toCharArray());
    }
    

    请注意,通过重写EncryptablePropertyResolver,您对前缀、后缀、EncryptablePropertyDetector和StringEncryptor的任何其他配置或重写都将停止工作,因为使用它们的是默认解析程序

    因为,对加密属性的检测和解密是MyEncryptablePropertyResolver内部的

    过滤器

    在jasypt-spring-boot:2.1.0版本引入了一个过滤器的新特性。

    filter允许您确定要考虑哪些属性或属性源进行解密。这是,甚至在检查要搜索或尝试解密的实际属性值之前。例如,默认情况下,名称以jasypt.encryptor开头的所有属性都将从检查中排除。这是为了在配置库bean时避免在加载时循环依赖。

    默认DefaultPropertyFilter

    image-20210507112557922

    该类的所有属性都是从JasyptEncryptorConfigurationProperties.PropertyConfigurationProperties.FilterConfigurationProperties类中读取

    该类只配置了以jasypt.encryptor名字开头的会被排除,其他都是没有配置的

    image-20210507112646430

    自定义EncryptablePropertyFilter

    您可以通过提供一个名为EncryptablePropertyFilter的EncryptablePropertyFilter类型的Bean来覆盖默认实现,或者如果您想提供自己的Bean名称,请覆盖属性jasypt.encryptor.property.filter-Bean并指定您想给Bean的名称。当提供这个时,您将负责检测您想要考虑解密的属性和/或属性源

        class MyEncryptablePropertyFilter implements EncryptablePropertyFilter {
        
            public boolean shouldInclude(PropertySource<?> source, String name) {
                return name.startsWith('encrypted.');
            }
        }
        @Bean(name="encryptablePropertyFilter")
            EncryptablePropertyFilter encryptablePropertyFilter() {
                return new MyEncryptablePropertyFilter();
            }
    

    请注意,要使此机制正常工作,不应提供自定义的EncryptablePropertyResolver,而应使用默认的解析器。如果您提供自定义EncryptablePropertyResolver,那么您将负责检测和解密属性的整个过程。

    测试

    配置:我这里自己注入了一个StringEncryptor,并自定义了MyEncryptablePropertyDetector,没有使用默认的解密探测器。

    /**
     * @author wen.jie
     * @date 2021/5/7 10:30
     */
    @Configuration
    public class MyConfig {
    
        @Bean("jasyptStringEncryptor")
        public StringEncryptor stringEncryptor() {
            PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
            SimpleStringPBEConfig config = new SimpleStringPBEConfig();
            config.setPassword("password");
            config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
            config.setKeyObtentionIterations("1000");
            config.setPoolSize("1");
            config.setProviderName("SunJCE");
            config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
            config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
            config.setStringOutputType("base64");
            encryptor.setConfig(config);
            return encryptor;
        }
    
        @Bean(name = "encryptablePropertyDetector")
        public EncryptablePropertyDetector encryptablePropertyDetector() {
            return new MyEncryptablePropertyDetector();
        }
    
        private static class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {
            @Override
            public boolean isEncrypted(String value) {
                if (value != null) {
                    return value.startsWith("ENC@");
                }
                return false;
            }
    
            @Override
            public String unwrapEncryptedValue(String value) {
                return value.substring("ENC@".length());
            }
        }
    }
    

    测试代码:

        @Autowired
        @Qualifier("jasyptStringEncryptor")
        StringEncryptor stringEncryptor;
    
        @Test
        void contextLoads() {
            String wj = stringEncryptor.encrypt("wj");
            System.out.println(wj);
        }
    

    测试结果:

    image-20210507121948586

    我们只需要在字符串前面加上ENC@,就可以解密:配置yml

    my:
      wj: ENC@8rwL/sEZlOr9hI9ifQj6GtjTjLKKFVfj992j6QZKs6ohPN676yvnHr02vycSiwwO
    

    测试:

        @Value("${my.wj}")
        private String myWj;
    
        @Test
        void test(){
            System.out.println(myWj);
        }
    

    image-20210507122121971

  • 相关阅读:
    谈软件开发工具的选择
    Windows下搭建Octopress博客
    Aspose Word模版使用总结篇2带示例
    强大的二分查找法(Binary Search)
    GhostDoc Pro v4.5.13017专业破解版本
    超炫的开源 JavaScript 物理引擎
    CQRS + DDD + MDP 实现快速应用程序开发
    数据结构之栈(Stack)与队列(Queue)
    插件框架实现
    集成服务监控器green.monitor发布
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14738704.html
Copyright © 2011-2022 走看看