Эта статья взята из«Введение в Spring Cloud Microservices, практический бой и продвинутый уровень»Эта книга. Некоторые из наиболее важной информации конфигурации, такие как конфиденциальная конфигурация пароля и тому подобное, мы хотим настроить шифрование хранения для обеспечения безопасности. Сама Apollo Framework не предоставляет функцию шифрования данных, если вы хотите добиться функции шифрования данных двумя способами, первым является изменение источника APOLLO, увеличение логики шифрования и дешифрования, вторая является относительно простым, основанным на сторонних рамках расшифровать данные.
jasypt-spring-boot — это фреймворк, разработанный на основе Spring Boot, который может автоматически расшифровывать зашифрованный контент в свойствах, в Apollo операции шифрования и дешифрования данных также могут быть реализованы с помощью фреймворка jasypt-spring-boot.
Адрес GitHub jasypt-spring-boot:Длина волны дисперсии на GitHub.com/u…
Зашифруйте конфигурацию, которую нам нужно зашифровать, с помощью метода, предоставленного jasypt-spring-boot, а затем настройте зашифрованный контент в Apollo.Когда проект начнется, jasypt-spring-boot расшифрует зашифрованную конфигурацию Apollo, чтобы пользователь получает расшифрованное содержимое.
Создайте новый проект Maven и добавьте зависимости Apollo и jasypt:
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>
<!--jasypt加密-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.16</version>
</dependency>
Добавьте следующую информацию о зависимости:
server.port=8081
app.id=SampleApp
apollo.meta=http://localhost:8080
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application
jasypt.encryptor.password=yinjihaunkey
- jasypt.encryptor.password: настроить зашифрованный ключ
Создайте зашифрованный служебный класс для конфигурации шифрования:
public class EncryptUtil {
/**
* 制表符、空格、换行符 PATTERN
*/
private static Pattern BLANK_PATTERN = Pattern.compile("\\s*|\t|\r|\n");
/**
* 加密Key
*/
private static String PASSWORD = "yinjihaunkey";
/**
* 加密算法
*/
private static String ALGORITHM = "PBEWithMD5AndDES";
public static Map<String, String> getEncryptedParams(String input) {
//输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
PrintStream cacheStream = new PrintStream(byteArrayOutputStream);
//更换数据输出位置
System.setOut(cacheStream);
//加密参数组装
String[] args = {"input=" + input, "password=" + PASSWORD, "algorithm=" + ALGORITHM};
JasyptPBEStringEncryptionCLI.main(args);
//执行加密后的输出
String message = byteArrayOutputStream.toString();
String str = replaceBlank(message);
int index = str.lastIndexOf("-");
//返回加密后的数据
Map<String, String> result = new HashMap<String, String>();
result.put("input", str.substring(index + 1));
result.put("password", PASSWORD);
return result;
}
/**
* 替换制表符、空格、换行符
*
* @param str
* @return
*/
private static String replaceBlank(String str) {
String dest = "";
if (!StringUtils.isEmpty(str)) {
Matcher matcher = BLANK_PATTERN.matcher(str);
dest = matcher.replaceAll("");
}
return dest;
}
public static void main(String[] args) {
System.out.println(getEncryptedParams("hello"));
}
}
Выполнив основной метод, вы можете получить следующий вывод:
{input=0JK4mrGjPUxkB4XuqEv2YQ==, password=yinjihaunkey}
Входные данные — это зашифрованное содержимое приветствия. Скопируйте входное значение и сохраните его в Apollo. Формат хранилища должен соответствовать определенным правилам:
test.input = ENC(0JK4mrGjPUxkB4XuqEv2YQ==)
Зашифрованное содержимое необходимо обернуть с помощью ENC, чтобы jasypt расшифровал значение.
Там, где он используется, конфигурация может быть введена непосредственно по имени, например:
@Value("${test.input}")
private String input;
Значение ввода — это значение после расшифровки, и пользователю не нужно заботиться о логике расшифровки.Структура Jasypt обрабатывается внутри.
Интеграция Джейпта Аполлона также имеет некоторые недостатки. В настоящее время я нашел только следующие проблемы:
-
Значение в проекте не обновляется после изменения значения в центре конфигурации
-
Значение, полученное путем внедрения объекта Config, не может быть расшифровано.
@ApolloConfig
private Config config;
@GetMapping("/config/getUserName3")
public String getUserName3() {
return config.getProperty("test.input", "yinjihuan");
}
Две проблемы, перечисленные выше, связаны с реализацией jasypt, что означает, что этот метод шифрования может подходить только для паролей базы данных и т. п. Его можно расшифровать при запуске и использовать только один раз. Если это какое-то сравнение, если основной бизнес конфигурация должна быть зашифрована, jasypt не может ее поддерживать и не может обновляться в режиме реального времени. В следующей главе я объясню, как изменить исходный код Apollo, чтобы решить эти две проблемы.
Расширенный Apollo для поддержки шифрования и дешифрования хранилища
В предыдущей главе было показано, как использовать jasypt для шифрования и расшифровки конфигурации в Apollo.Основные требования могут быть выполнены, но все же есть некоторые недостатки.
Jasypt расшифровывает конфигурацию только в формате ENC (xx) в Spring при запуске и не может быть обновлен при изменении конфигурации. Поскольку сама структура Apollo не имеет этой функции шифрования и дешифрования конфигурации, если мы хотим реализовать шифрование и дешифрование и иметь возможность динамически обновляться, нам необходимо внести некоторые изменения в исходный код Apollo, чтобы соответствовать требованиям.
Модификация исходного кода также нуждается в переупаковке.Автор представляет здесь относительно простой метод реализации, который заключается в создании имени класса, точно такого же, как в среде Apollo, чтобы покрыть его, чтобы клиент, который уже используется, не нужно заменять.
Если содержимое, хранящееся в центре конфигурации, зашифровано, это означает, что конфигурация, извлеченная клиентом Apollo из центра конфигурации, также зашифрована.Нам нужно расшифровать конфигурацию после извлечения конфигурации, а затем выполнить следующий процесс, например как Привязать к весне. После включения этой точки обслуживания зашифрованное содержимое центра конфигурации может автоматически стать расшифрованным открытым текстом, прозрачным для пользователя.
Проанализировав исходный код Apollo, автор нашел наиболее подходящую точку входа для этого.Этот класс — com.ctrip.framework.apollo.internals.DefaultConfig.DefaultConfig — класс реализации интерфейса Coonfig.Инициализация и получение конфигурации будет после обработки DefaultConfig.
Внутри DefaultConfig есть метод updateConfig для обновления конфигурации, в котором зашифрованные данные могут быть расшифрованы:
private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) {
Set<Object> keys = newConfigProperties.keySet();
for (Object k : keys) {
String key = k.toString();
String value = newConfigProperties.getProperty(key);
// 加密Value
if (value.startsWith("ENC(") && value.endsWith(")")) {
logger.debug("加密Value {}", value);
// 解密然后重新赋值
try {
String decryptValue = AesEncryptUtils.aesDecrypt(value.substring(3, value.length()-1), DECRYPT_KEY);
newConfigProperties.setProperty(key, decryptValue);
} catch (Exception e) {
logger.error("加密配置解密失败", e);
}
}
}
m_configProperties.set(newConfigProperties);
m_sourceType = sourceType;
}
Здесь используются AES для дешифровки, что означает, что зашифрованное содержание центра конфигурации также необходимо зашифровать с тем же алгоритмом шифрования. Что касается формата, формат ENC (XX) используется для идентификации того, что это зашифрованный контент конфигурации Отказ После дешифрования, расшифрованный содержание открытого текста переназначен к свойствам, а другие процессы остаются неизменными.
Создайте зашифрованный тестовый класс, зашифруйте конфигурацию, скопируйте хранилище в Apollo
public class Test {
public static void main(String[] args) {
String msg = "hello yinjihaun";
try {
String encryptMsg = AesEncryptUtils.aesEncrypt(msg, "1111222233334444");
System.out.println(encryptMsg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Результат выглядит следующим образом:
Ke4LIPGOp3jCwbIHtmhmBA==
Чтобы сохранить в Apollo, вам необходимо обернуть зашифрованный контент с помощью ENC следующим образом:
test.input = ENC(Ke4LIPGOp3jCwbIHtmhmBA==)
По-прежнему используя предыдущий код для тестирования, методы получения конфигурации и внедрения Spring могут успешно получить расшифрованные данные, а после изменения центра конфигурации их также можно передать клиенту для успешной расшифровки в режиме реального времени.
Эта статья взята из«Введение в Spring Cloud Microservices, практический бой и продвинутый уровень»Эта книга.