<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot 配置文件這樣加密,才足夠安全!

          共 45276字,需瀏覽 91分鐘

           ·

          2022-11-29 12:20

          關(guān)注我們,設(shè)為星標(biāo),每天7:40不見不散,架構(gòu)路上與您共享

          回復(fù)架構(gòu)師獲取資源


          大家好,我是你們的朋友架構(gòu)君,一個會寫代碼吟詩的架構(gòu)師。

          'javajgs.com';


          原文:
          blog.csdn.net/HLH_2021/article/details/119854365



          1. 前景


          在使用Springboot時,通常很多信息都是在application.yml中直接明文配置的,比如數(shù)據(jù)庫鏈接信息,redis鏈接信息等等。但是這樣是不安全的。

          所以需要對敏感數(shù)據(jù)進(jìn)行加密,這樣防止密碼泄露

          Jasypt這個庫為我們解決了這個問題,實(shí)現(xiàn)了springboot配置的自定加密加密

          2. 簡單使用

          源碼對應(yīng)地址:

          http://gitlab.sea-clouds.cn/csdn/spring-boot-csdn/-/tree/master/05-spring-boot-jasypt

          2.1 引入依賴
          <properties>
              <maven.compiler.source>11</maven.compiler.source>
              <maven.compiler.target>11</maven.compiler.target>
          </properties>

          <dependencyManagement>
              <dependencies>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-dependencies</artifactId>
                      <version>2.4.0</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
              </dependencies>
          </dependencyManagement>

          <dependencies>
              <!-- web 和 測試 -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
              </dependency>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <scope>test</scope>
              </dependency>
              <!-- jdbc -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-jdbc</artifactId>
              </dependency>
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
              </dependency>

              <!-- jasypt 加密 -->
              <dependency>
                  <groupId>com.github.ulisesbocchio</groupId>
                  <artifactId>jasypt-spring-boot-starter</artifactId>
                  <version>3.0.3</version>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
          </dependencies>
          2.2 配置application信息

          jasypt配置

          jasypt:
            encryptor:
              # 加密算法
              algorithm: PBEWITHHMACSHA512ANDAES_256
              # 加密使用的鹽
              password: jaspyt_password
          2.3 加密解密測試
          /**
           * @author HLH
           * @description: 加密解密測試
           */

          @SpringBootTest
          @RunWith(SpringRunner.class)
          public class JasyptTest 
          {

              @Autowired
              private StringEncryptor stringEncryptor;

              /**
               * 加密解密測試
               */

              @Test
              public void jasyptTest() {
                  // 加密
                  System.out.println(stringEncryptor.encrypt("root"));    // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
                  // 解密
                  System.out.println(stringEncryptor.decrypt("JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg"));    // root
              }

              /**
               * 手動測試
               */

              @Test
              public void test() {
                  PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
                  SimpleStringPBEConfig config = new SimpleStringPBEConfig();
                  config.setPassword("jaspyt_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);
                  System.out.println(encryptor.encrypt("root"));    // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
              }

          }


          3. 使用Jasypt加密后的字符串代替數(shù)據(jù)庫密碼

          3.1 使用加密類進(jìn)行加密

          密碼 root 加密之后 XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1

          /**
           * 數(shù)據(jù)庫密碼加密
           */

          @Test
          public void encryptPasswored() {
              // 加密
              System.out.println(stringEncryptor.encrypt("root"));    // XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
              // 解密
              System.out.println(stringEncryptor.decrypt("XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1"));    // root
          }
          3.2 替換數(shù)據(jù)庫配置
          spring:
            datasource:
              driver-class-name: com.mysql.cj.jdbc.Driver
              url: jdbc:mysql://192.168.10.31/mp
              username: root
              # 使用ENC()包裹,標(biāo)識為加密之后的,否則無法解密,會報錯
              password: ENC(R2H69h1aEgJ3EDPLXAVQ5CxZJWtl8EvqIJUtlATRt6om4w46/J+blu2JAvkR7Yvp)
          3.3 測試
          @Autowired
          private DataSource dataSource;
          /**
           * 測試加密之后的數(shù)據(jù)源使用是否正常
           *  查看是否能正常獲取鏈接
           */

          @Test
          public void datasourceTest() throws SQLException {
              Connection connection = dataSource.getConnection();
              System.out.println(connection);     // HikariProxyConnection@1487059223 wrapping com.mysql.cj.jdbc.ConnectionImpl@48904d5a
              connection.close();
          }


          4. Jasypt配置詳解


          所有配置都在JasyptEncryptorConfigurationProperties類中定義,我們只需要在yml中配置屬性,即可達(dá)到重寫的目的

          Jasypt使用StringEncryptor來解密屬性。如果Spring上下文中找不到自定義的StringEncryptor,就會自動創(chuàng)建一個,可以通過以下屬性進(jìn)行配置

          唯一需要的屬性是加密的鹽,其余的可以使用默認(rèn)值。雖然所有這些屬性都可以在屬性文件中生命,但加密所使用的鹽不應(yīng)該存儲在屬性文件中,而是應(yīng)該通過系統(tǒng)屬性、命令行參數(shù)或者環(huán)境變量傳遞,只要他的名稱是jasypt.encryptor.password,它就可以工作。

          倒數(shù)第二個屬性jasypt.encryptor.proxyPropertySources用于只是jasypt spring boot如何攔截屬性值進(jìn)行解密。默認(rèn)值false使用PropertySourceEnumerablePropertySourceMapPropertySource的自定義包裝器實(shí)現(xiàn)。當(dāng)為true時,攔截機(jī)制將在每個特定的PropertySource實(shí)現(xiàn)上使用CGLib代理。在某些必須保留原始PropertySource類型的場景中,這可能很有用。

          5. 自定義加密

          默認(rèn)情況下,bean容器會配置LazyJasyptSringEncryptor

          5.1 官方配置

          官方配置的Bean都是在EncryptablePropertyResolverConfiguration中進(jìn)行注入的

          @Bean(
              name = {"lazyJasyptStringEncryptor"}
          )
          public StringEncryptor stringEncryptor(EnvCopy envCopy, BeanFactory bf) {
              String customEncryptorBeanName = envCopy.get().resolveRequiredPlaceholders(ENCRYPTOR_BEAN_PLACEHOLDER);
              boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.bean");
              return new DefaultLazyEncryptor(envCopy.get(), customEncryptorBeanName, isCustom, bf);
          }
          5.2 自定義加密

          可以在Spring上下文中共自定義自己的StringEncryptor Bean,默認(rèn)的加密程序?qū)⒈缓雎?/span>

          注意

          自定義Bean的名稱必須為 jasyptStringEncryptor,否則解密不生效

          自定義注入bean

          /**
           * 加入 StringEncryptor 加密解密類
           *      beanName 必須為 jasyptStringEncryptor 才能是自定義的生效
           *      configProps 為jasypt框架中讀取的配置類,就不用自己讀取了
           */

          @Bean("jasyptStringEncryptor")
          public StringEncryptor jasyptStringEncryptor(Singleton<JasyptEncryptorConfigurationProperties> configProps) {
              PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
              JasyptEncryptorConfigurationProperties jasyptProperties = configProps.get();
              SimpleStringPBEConfig config = new SimpleStringPBEConfig();
              config.setPassword(jasyptProperties.getPassword());
              config.setAlgorithm(jasyptProperties.getAlgorithm());
              config.setKeyObtentionIterations(jasyptProperties.getKeyObtentionIterations());
              config.setPoolSize(jasyptProperties.getPoolSize());
              config.setProviderName(jasyptProperties.getProviderName());
              config.setSaltGeneratorClassName(jasyptProperties.getSaltGeneratorClassname());
              config.setIvGeneratorClassName(jasyptProperties.getIvGeneratorClassname());
              config.setStringOutputType(jasyptProperties.getStringOutputType());
              encryptor.setConfig(config);
              return encryptor;
          }


          6. 自定義屬性探測器


          屬性探測器為判斷一個屬性值是否為加密后的字符串,并且截取真實(shí)字符串

          6.1 官方處理流程

          6.1.2 注入

          EncryptablePropertyResolverConfiguration類中

          @Bean(
              name = {"lazyEncryptablePropertyDetector"}
          )
          public EncryptablePropertyDetector encryptablePropertyDetector(EnvCopy envCopy, BeanFactory bf) {
              String customDetectorBeanName = envCopy.get().resolveRequiredPlaceholders(DETECTOR_BEAN_PLACEHOLDER);
              boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.property.detector-bean");
              return new DefaultLazyPropertyDetector(envCopy.get(), customDetectorBeanName, isCustom, bf);
          }

          6.1.2 DefaultLazyPropertyDetector

          默認(rèn)實(shí)現(xiàn)是DefaultLazyPropertyDetector,具體代碼是

          @Slf4j
          public class DefaultLazyPropertyDetector implements EncryptablePropertyDetector {

              // 屬性探測器
              private Singleton<EncryptablePropertyDetector> singleton;

              public DefaultLazyPropertyDetector(ConfigurableEnvironment environment, String customDetectorBeanName, boolean isCustom, BeanFactory bf) {
                  singleton = new Singleton<>(() ->
                          Optional.of(customDetectorBeanName)
                                  .filter(bf::containsBean)
                                  .map(name -> (EncryptablePropertyDetector) bf.getBean(name))
                                  .map(tap(bean -> log.info("Found Custom Detector Bean {} with name: {}", bean, customDetectorBeanName)))
                                  .orElseGet(() -> {
                                      if(isCustom) {
                                          throw new IllegalStateException(String.format("Property Detector custom Bean not found with name '%s'", customDetectorBeanName));
                                      }
                                      log.info("Property Detector custom Bean not found with name '{}'. Initializing Default Property Detector", customDetectorBeanName);
                                      return createDefault(environment);
                                  }));
              }

              public DefaultLazyPropertyDetector(ConfigurableEnvironment environment) {
                  // 創(chuàng)建一個屬性探測器
                  singleton = new Singleton<>(() -> createDefault(environment));
              }

              private DefaultPropertyDetector createDefault(ConfigurableEnvironment environment) {
                  // 讀取所有的屬性
                  JasyptEncryptorConfigurationProperties props = JasyptEncryptorConfigurationProperties.bindConfigProps(environment);
                  // 創(chuàng)建一個默認(rèn)的屬性探測器,讀取配置文件中的前綴和后綴
                  return new DefaultPropertyDetector(props.getProperty().getPrefix(), props.getProperty().getSuffix());
              }

              /**
                * 是否為解密格式字符串
                */

              @Override
              public boolean isEncrypted(String property) {
                  return singleton.get().isEncrypted(property);
              }

              /**
                * 獲取真是的加密后的字符串
                */

              @Override
              public String unwrapEncryptedValue(String property) {
                  return singleton.get().unwrapEncryptedValue(property);
              }
          }

          在其中是創(chuàng)建了一個DefaultPropertyDetector對象

          6.1.3 DefaultPropertyDetector

          public class DefaultPropertyDetector implements EncryptablePropertyDetector {

              // 默認(rèn)前綴和后綴
              private String prefix = "ENC(";
              private String suffix = ")";

              public DefaultPropertyDetector() {
              }

              public DefaultPropertyDetector(String prefix, String suffix) {
                  Assert.notNull(prefix, "Prefix can't be null");
                  Assert.notNull(suffix, "Suffix can't be null");
                  this.prefix = prefix;
                  this.suffix = suffix;
              }

              @Override
              public boolean isEncrypted(String property) {
                  if (property == null) {
                      return false;
                  }
                  final String trimmedValue = property.trim();
                  return (trimmedValue.startsWith(prefix) &&
                          trimmedValue.endsWith(suffix));
              }

              // 去掉前綴和后綴
              @Override
              public String unwrapEncryptedValue(String property) {
                  return property.substring(
                          prefix.length(),
                          (property.length() - suffix.length()));
              }
          }
          6.2 自定義規(guī)則探測器

          兩種方式自定義

          • 提供一個名為encryptablePropertyDetectorEncryptablePropertyDetector類型的Bean來覆蓋默認(rèn)的實(shí)現(xiàn)
          • 如果提供的bean名稱不為encryptablePropertyDetector,可以通過修改yml中的屬性jasypt.encryptor.property.detector-Bean為自己的bean的名稱。

          方式

          • 要么自定義類
          • 要么修改yml中的前綴和后綴

          6.2.1 自定義屬性探測器,加入容器

          /**
           * 自定義屬性探測器
           *  beanName為 encryptablePropertyDetector
           */

          @Bean(name = "encryptablePropertyDetector")
          public EncryptablePropertyDetector encryptablePropertyDetector() {
              return new MyEncryptablePropertyDetector();
          }


          /**
           * @author HLH
           * @description: 自定義的屬性探測器
           * @email [email protected]
           * @date : Created in 2021/8/19 20:01
           */

          public class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {

              /**
               * 是否為可以解密的字符串
               * @param value 全部的字符串
               * @return 是否是解密的字符串,true,是,false,否
               */

              @Override
              public boolean isEncrypted(String value) {
                  if (value != null) {
                      return value.startsWith("ENC@");    // 自定義規(guī)則為 ENC@開頭
                  }
                  return false;
              }

              /**
               * 截取到除了標(biāo)識之后的值
               * @param value 帶前綴
               * @return string 去掉標(biāo)識符的字符串
               */

              @Override
              public String unwrapEncryptedValue(String value) {
                  return value.substring("ENC@".length());        // 截取ENC@之后的字符串
              }
          }

          yml中的配置

          jasypt:
            encryptor:
              # 加密算法
              algorithm: PBEWITHHMACSHA512ANDAES_256
              # 加密使用的鹽
              password: jaspyt_password
              property:
                 # 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
                 # prefix: ENC_(
                 # suffix: )
                 # 自定義的屬性探測器,如果這個是自定義的,那么上述的前綴后綴不生效
                 detector-bean: encryptablePropertyDetector

          6.2.2 修改yml中的配置

          spring:
            datasource:
              driver-class-name: com.mysql.cj.jdbc.Driver
              url: jdbc:mysql://192.168.10.31/mp
              username: root
              # 使用ENC()包裹,標(biāo)識為加密之后的,否則無法解密,會報錯
              # 自定義規(guī)則之后,使用ENC@開頭
              password: ENC@JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg


          7. 自定義規(guī)則的前綴和后綴


          在上述說明中,在DefaultLazyPropertyDetector中是默認(rèn)是通過配置文件中的規(guī)則進(jìn)行匹配的。默認(rèn)規(guī)則是以ENC(開頭,以)結(jié)尾,可以復(fù)寫配置來自定義前綴和后綴

          上面第6條是自定義了屬性探測器,包括了定義規(guī)則和過濾字符串

          如果只是想自定義前綴和后綴,那么可以直接修改yml中的配置來修改自定義的前綴和后綴

          jasypt:
            encryptor:
              # 加密算法
              algorithm: PBEWITHHMACSHA512ANDAES_256
              # 加密使用的鹽
              password: jaspyt_password
              property:
                # 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
                prefix: ENC(
                suffix: )


          8. 直接自定義解密規(guī)則


          上述6和7自定義了解密字符串的規(guī)則和解密字符串的過濾,但是真正的解析處理還是Jasypt框架來負(fù)責(zé)的。我們也可以直接自定義解密的一系列流程。

          8.1 官方處理流程

          8.1.1 官方的注入

          EncryptablePropertyResolverConfiguration類中

          @Bean(
              name = {"lazyEncryptablePropertyResolver"}
          )
          public EncryptablePropertyResolver encryptablePropertyResolver(@Qualifier("lazyEncryptablePropertyDetector") EncryptablePropertyDetector propertyDetector, @Qualifier("lazyJasyptStringEncryptor") StringEncryptor encryptor, BeanFactory bf, EnvCopy envCopy, ConfigurableEnvironment environment) {
              String customResolverBeanName = envCopy.get().resolveRequiredPlaceholders(RESOLVER_BEAN_PLACEHOLDER);
              boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.property.resolver-bean");
              return new DefaultLazyPropertyResolver(propertyDetector, encryptor, customResolverBeanName, isCustom, bf, environment);
          }

          默認(rèn)注入的是DefaultLazyPropertyResolver但是在其中創(chuàng)建的是EncryptablePropertyResolver對象

          8.1.2 EncryptablePropertyResolver

          1. 官方默認(rèn)是通過EncryptablePropertyResolver接口來處理解析字符串的
          public interface EncryptablePropertyResolver {

              /**
               * 處理所有屬性的解密處理
               * 如果為檢測到加密規(guī)則,那么返回實(shí)際為相同的字符創(chuàng)
               *
               * @param value 屬性值
               * @return 如果值未加密,返回原值,如果加密,返回加密之后的值
               */

              String resolvePropertyValue(String value);
          }
          1. 其真實(shí)性使用的實(shí)現(xiàn)類是DefaultPropertyResolver用來真正處理解析。就是通過調(diào)用上文中的StringEncryptor處理解密,使用EncryptablePropertyDetector定義的解密字符串規(guī)則定義是否為加密的字符串
          public class DefaultPropertyResolver implements EncryptablePropertyResolver {

              private final Environment environment;
              // 默認(rèn)的或者自定義的StringEncryptor,用來解密
              private StringEncryptor encryptor;
              // 默認(rèn)的或者自定義的EncryptablePropertyDetector,用來定義是否為加密的字符串
              private EncryptablePropertyDetector detector;

              public DefaultPropertyResolver(StringEncryptor encryptor, Environment environment) {
                  this(encryptor, new DefaultPropertyDetector(), environment);
              }

              public DefaultPropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector, Environment environment) {
                  this.environment = environment;
                  Assert.notNull(encryptor, "String encryptor can't be null");
                  Assert.notNull(detector, "Encryptable Property detector can't be null");
                  this.encryptor = encryptor;
                  this.detector = detector;
              }

              @Override
              public String resolvePropertyValue(String value) {
                  return Optional.ofNullable(value)
                          .map(environment::resolvePlaceholders)
                          .filter(detector::isEncrypted)  // 如果經(jīng)過屬性探測器確認(rèn)的,才繼續(xù)
                          .map(resolvedValue -> {
                              try {
                                  String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 過濾加密規(guī)則后的字符串
                                  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);
              }
          }
          8.2 自定義的解密邏輯

          編寫自己的解密邏輯類

          加入spring容器,命名為encryptablePropertyResolver,或者通過yml方式配置自定義bean名稱

          @Bean("encryptablePropertyResolver")
          public EncryptablePropertyResolver encryptablePropertyResolver(
                  StringEncryptor jasyptStringEncryptor, EncryptablePropertyDetector encryptablePropertyDetector)
           
          {
              return new MyEncryptablePropertyResolver(jasyptStringEncryptor, encryptablePropertyDetector);
          }

          /**
           * @author HLH
           * @description: 直接自定義解密規(guī)則
           * @email [email protected]
           * @date : Created in 2021/8/21 21:22
           */

          public class MyEncryptablePropertyResolver implements EncryptablePropertyResolver {

              // 處理解密
              private final StringEncryptor encryptor;
              // 屬性探測器
              private final EncryptablePropertyDetector detector;

              public MyEncryptablePropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector) {
                  this.encryptor = encryptor;
                  this.detector = detector;
              }

              /**
               * 處理真正的解密邏輯
               * @param value 原始值
               * @return 如果值未加密,返回原值,如果加密,返回加密之后的值
               */

              @Override
              public String resolvePropertyValue(String value) {
                  return Optional.ofNullable(value)
                          .filter(detector::isEncrypted)  // 如果經(jīng)過屬性探測器確認(rèn)的,才繼續(xù)
                          .map(resolvedValue -> {
                              try {
                                  String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 過濾加密規(guī)則后的字符串
                                  return encryptor.decrypt(unwrappedProperty); // 解密
                              } catch (EncryptionOperationNotPossibleException e) {
                                  throw new DecryptionException("Unable to decrypt: " + value + ". Decryption of Properties failed,  make sure encryption/decryption " +
                                          "passwords match", e);
                              }
                          })
                          .orElse(value);
              }
          }

          yml配置

          jasypt:
            encryptor:
              # 加密算法
              algorithm: PBEWITHHMACSHA512ANDAES_256
              # 加密使用的鹽
              password: jaspyt_password
              property:
                 # 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
                 # prefix: ENC_(
                 # suffix: )
                 # 自定義的屬性探測器,如果這個是自定義的,那么上述的前綴后綴不生效
                 detector-bean: encryptablePropertyDetector
                 # 自定義解密邏輯類 如果配置了,默認(rèn)的解析器將不工作
                 resolver-bean: encryptablePropertyResolver


          9. 自定義過濾器


          在Jasypt-spring-boot中,引入了過濾器

          過濾器filter允許過濾某些屬性,不進(jìn)行解密。默認(rèn)情況下,jasypt.encryptor開頭的所有屬性都會將從檢查項中排除掉。這是為了配置Bean,在加載時循環(huán)依賴

          9.1 默認(rèn)處理流程

          9.1.1 官方的注入

          EncryptablePropertyResolverConfiguration類中

          @Bean(
              name = {"lazyEncryptablePropertyFilter"}
          )
          public EncryptablePropertyFilter encryptablePropertyFilter(EnvCopy envCopy, ConfigurableBeanFactory bf) {
              String customFilterBeanName = envCopy.get().resolveRequiredPlaceholders(FILTER_BEAN_PLACEHOLDER);
              boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.property.filter-bean");
              return new DefaultLazyPropertyFilter(envCopy.get(), customFilterBeanName, isCustom, bf);
          }

          于上面的邏輯一樣,在DefaultLazyPropertyFilter中其實(shí)是新建了一個EncryptablePropertyFilter對象,默認(rèn)實(shí)現(xiàn)類是DefaultPropertyFilter

          9.1.2 DefaultPropertyFilter

          public class DefaultPropertyFilter implements EncryptablePropertyFilter {

              // 過濾的和包含的,優(yōu)先讀取配置文件的
              private final List<String> includeSourceNames;
              private final List<String> excludeSourceNames;
              private final List<String> includePropertyNames;
              private final List<String> excludePropertyNames;

              public DefaultPropertyFilter() {
                  includeSourceNames = null;
                  includePropertyNames = null;
                  excludeSourceNames = null;
                  excludePropertyNames = null;
              }

              public DefaultPropertyFilter(List<String> includeSourceNames, List<String> excludeSourceNames, List<String> includePropertyNames, List<String> excludePropertyNames) {
                  this.includeSourceNames = includeSourceNames;
                  this.excludeSourceNames = excludeSourceNames;
                  this.includePropertyNames = includePropertyNames;
                  this.excludePropertyNames = excludePropertyNames;
              }

              // 是否攔截
              @Override
              public boolean shouldInclude(PropertySource<?> source, String name) {
                  // 如果上述四個都沒有配置,那么全部放行
                  if (isIncludeAll()) {
                      return true;
                  }

                  // 如果是不包含的,返回false,就過濾掉了
                  if (isMatch(source.getName(), excludeSourceNames) || isMatch(name, excludePropertyNames)) {
                      return false;
                  }

                  // 如果是包含的,就放行
                  return isIncludeUnset() || isMatch(source.getName(), includeSourceNames) || isMatch(name, includePropertyNames);

              }

              private boolean isIncludeAll() {
                  return isIncludeUnset() && isExcludeUnset();
              }

              private boolean isIncludeUnset() {
                  return isEmpty(includeSourceNames) && isEmpty(includePropertyNames);
              }

              private boolean isExcludeUnset() {
                  return isEmpty(excludeSourceNames) && isEmpty(excludePropertyNames);
              }

              private boolean isEmpty(List<String> patterns) {
                  return patterns == null || patterns.isEmpty();
              }

              // 傳遞的配置其實(shí)是正則,進(jìn)行正則匹配
              private boolean isMatch(String name, List<String> patterns) {
                  return name != null && !isEmpty(patterns) && patterns.stream().anyMatch(name::matches);
              }
          }
          9.2 自定義過濾器

          方式

          • 要么自定義過濾器
          • 要么修改jasypt.encryptor.property.include-names或者jasypt.encryptor.property.exclude-names配置攔截和放行的資源key

          自定義過濾器類

          加入spring容器,命名為encryptablePropertyFilter

          /**
           * 自定義的屬性攔截器
           * @param configProps Jasypt官方讀取的配置集合
           * @return 自定義屬性攔截器
           */

          @Bean(name="encryptablePropertyFilter")
          public EncryptablePropertyFilter encryptablePropertyFilter(
                  Singleton<JasyptEncryptorConfigurationProperties> configProps)
           
          {
              return new MyEncryptablePropertyFilter(configProps.get());
          }

          /**
           * @author HLH
           * @description: 自定義的屬性過濾器
           * @email [email protected]
           * @date : Created in 2021/8/22 13:37
           */

          public class MyEncryptablePropertyFilter implements EncryptablePropertyFilter {

              /** jasypt 的所有配置*/
              JasyptEncryptorConfigurationProperties jasyptProperties;

              public MyEncryptablePropertyFilter(JasyptEncryptorConfigurationProperties jasyptProperties) {
                  this.jasyptProperties = jasyptProperties;
              }

              @Override
              public boolean shouldInclude(PropertySource<?> source, String name) {
                  List<String> excludeNames = jasyptProperties.getProperty().getFilter().getExcludeNames();
                  List<String> includeNames = jasyptProperties.getProperty().getFilter().getIncludeNames();
                  if (CollectionUtils.isEmpty(includeNames) && CollectionUtils.isEmpty(excludeNames)) {
                      return true;
                  }

                  if (isMatch(source.getName(), excludeNames) || isMatch(source.getName(), excludeNames)) {
                      return false;
                  }

                  return CollectionUtils.isEmpty(includeNames) ||
                          isMatch(source.getName(), includeNames) ||
                          isMatch(name, includeNames);

              }

              /**
               * 正則判斷,如果滿足,返回true,如果不滿足,返回false
               * @param name 配置的key
               * @param patterns 正則列表
               * @return 如果滿足,返回true,如果不滿足,返回false
               */

              private boolean isMatch(String name, List<String> patterns) {
                  return name != null && !CollectionUtils.isEmpty(patterns) && patterns.stream().anyMatch(name::matches);
              }

          }

          yml配置

          jasypt:
            encryptor:
              # 加密算法
              algorithm: PBEWITHHMACSHA512ANDAES_256
              # 加密使用的鹽
              password: jaspyt_password
              property:
                # 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
                # prefix: ENC_(
                # suffix: )
                # 自定義的屬性探測器,如果這個是自定義的,那么上述的前綴后綴不生效
                detector-bean: encryptablePropertyDetector
                # 自定義解密邏輯類 如果配置了,默認(rèn)的解析器將不工作
                resolver-bean: encryptablePropertyResolver
                # 過濾器的bean
                filter-bean: encryptablePropertyFilter
                # 過濾器配置,正則
                filter:
                  # 默認(rèn)包含的
                  include-names:
                  # 默認(rèn)攔截的,默認(rèn)攔截jasypt.encryptor的配置
                  exclude-names:
                    - ^jasypt\.encryptor\.*


          10. 使用mvn插件加密解密


          使用代碼的方式比較不方便,還需要編碼實(shí)現(xiàn),如果不想編碼,簡單的進(jìn)行加密解密,就可以使用maven的插件,使用mvn命令進(jìn)行加密解密

          10.1 引入Jasypt的maven插件
          <build>
              <plugins>
                  <!-- Jasypt 的maven插件 -->
                  <plugin>
                      <groupId>com.github.ulisesbocchio</groupId>
                      <artifactId>jasypt-maven-plugin</artifactId>
                      <version>3.0.2</version>
                  </plugin>
              </plugins>
          </build>
          10.2 加密

          使用jasypt-maven-plugin插件加密明文密碼:(如果配置項是默認(rèn)值,可以不指定)

          mvn jasypt:encrypt-value -Djasypt.encryptor.password="jaspyt_password" -Djasypt.plugin.value="root" -Djasypt.encryptor.algorithm="PBEWITHHMACSHA512ANDAES_256"
          • jasypt.encryptor.password 是秘鑰,盡量復(fù)雜!不能放在代碼和配置文件里面!不能泄漏
          • jasypt.plugin.value 是要加密的明文密碼
          • jasypt.encryptor.algorithm默認(rèn)加密算法是PBEWITHHMACSHA512ANDAES_256,需要有JCE(Java Cryptography Extension)支持,如果不想安裝JCE,可以使用PBEWithMD5AndDES算法。windows下的jdk自帶

          進(jìn)入項目所在的目錄,輸入命令,成功加密

          10.3 解密

          使用jasypt-maven-plugin插件解密密文密碼:(如果配置項是默認(rèn)值,可以不指定)

          mvn jasypt:decrypt-value -Djasypt.encryptor.password="jaspyt_password" -Djasypt.plugin.value="pqsp6kvVfBcKoEltxP9MilGGRo8EE506mDWAuTFIKePDXMeArta13bT6Hl8QqVlC" -Djasypt.encryptor.algorithm="PBEWITHHMACSHA512ANDAES_256"
          • jasypt.encryptor.password 是秘鑰,盡量復(fù)雜!不能放在代碼和配置文件里面!不能泄漏
          • jasypt.plugin.value 是要加密的明文密碼,有ENC()包裹或者不包裹都可以
          • jasypt.encryptor.algorithm默認(rèn)加密算法是PBEWITHHMACSHA512ANDAES_256,需要有JCE(Java Cryptography Extension)支持,如果不想安裝JCE,可以使用PBEWithMD5AndDES算法。windows下的jdk自帶

          進(jìn)入項目所在的目錄,輸入命令,成功加密


          11. 思維導(dǎo)圖


          最后再來一張思維導(dǎo)圖




          到此文章就結(jié)束了。Java架構(gòu)師必看一個集公眾號、小程序、網(wǎng)站(3合1的文章平臺,給您架構(gòu)路上一臂之力,javajgs.com)。如果今天的文章對你在進(jìn)階架構(gòu)師的路上有新的啟發(fā)和進(jìn)步,歡迎轉(zhuǎn)發(fā)給更多人。歡迎加入架構(gòu)師社區(qū)技術(shù)交流群,眾多大咖帶你進(jìn)階架構(gòu)師,在后臺回復(fù)“加群”即可入群。

          第23期已結(jié)束!第24期已開始,11月1號截止



          這些年小編給你分享過的干貨


          1.idea永久激活碼(親測可用)

          2.優(yōu)質(zhì)ERP系統(tǒng)帶進(jìn)銷存財務(wù)生產(chǎn)功能(附源碼)

          3.優(yōu)質(zhì)SpringBoot帶工作流管理項目(附源碼)

          4.最好用的OA系統(tǒng),拿來即用(附源碼)

          5.SBoot+Vue外賣系統(tǒng)前后端都有(附源碼

          6.SBoot+Vue可視化大屏拖拽項目(附源碼)


          轉(zhuǎn)發(fā)在看就是最大的支持??

          瀏覽 76
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲国产另类无码 | 亚洲日本香蕉 | 大鸡巴AV在线 | 久久久久久无码麻豆 | 蜜逃视频观看 |