SpringBoot实现自定义environment中的value加密

environment中的value为什么要加密?

未经过加密的配置文件,密码均是采用明文密码,很容易导致信息泄露。

SpringBoot environment中的value加密代码如下

java 复制代码
package com.xxx.core.encryption;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

import java.util.Map;

/**
 * @author HanKeQi
 * @date 2023/9/4
 */
@Slf4j
public class EnableEncryptionData implements BeanFactoryPostProcessor, Ordered {

    private final ConfigurableEnvironment environment;

    //根据自己需求自定义
    private static final String PREFIX = "ENC(";

    private static final String SUFFIX = ")";

    /**
     * 扫描自定义配置的文件
     */
    private static final String BOOTSTRAP_CONFIGURE = "bootstrap";

    public EnableEncryptionData(ConfigurableEnvironment environment) {
        this.environment = environment;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        MutablePropertySources propertySources = environment.getPropertySources();
        for (PropertySource<?> propertySource: propertySources){
            if (propertySource instanceof OriginTrackedMapPropertySource){
                OriginTrackedMapPropertySource originTrackedMapPropertySource = (OriginTrackedMapPropertySource) propertySource;
                String activeName = originTrackedMapPropertySource.getName();
                Map<String, Object> activeSource = (Map<String, Object>)propertySources.get(activeName).getSource();
                Map<String, Object> newConfigMap = Maps.newHashMap();
                activeSource.forEach((k,v)->{
                    if (v instanceof OriginTrackedValue){
                        Object valueObj = ((OriginTrackedValue) v).getValue();
                        if (valueObj instanceof String){
                            String valueEncryptionStr = (String) valueObj;
                            if (!StringUtils.isEmpty(valueEncryptionStr) && valueEncryptionStr.startsWith(PREFIX) && valueEncryptionStr.endsWith(SUFFIX)){
                                try {
                                    valueEncryptionStr = getEncryptionStr(valueEncryptionStr);
                                    valueEncryptionStr = AesUtils.decodeStr(valueEncryptionStr, AesUtils.P_KEY);
                                    newConfigMap.put(k, valueEncryptionStr);
                                    return;
                                }catch (Exception e){
                                    e.printStackTrace();
                                }
                            }

                        }

                    }
                    newConfigMap.put(k, v);
                });
                propertySources.replace(activeName, new OriginTrackedMapPropertySource(activeName , newConfigMap, true));
            }
        }



    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 100;
    }

    /**
     * 获取加密后的信息
     * @param encryptionStr
     * @return
     */
    private static String getEncryptionStr(String encryptionStr){
        encryptionStr = encryptionStr.substring(PREFIX.length());
        encryptionStr = encryptionStr.substring(0, encryptionStr.length()-SUFFIX.length());
        return encryptionStr;
    }
}

springboot 配置Configuration

java 复制代码
package com.xxx.core.encryption;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * @author HanKeQi
 * @date 2022/10/30
 */
@Configuration
public class EnvironmentConfig {

    @Bean
    public static EnableEncryptionData enableEncryptionData(final ConfigurableEnvironment environment) {

        return new EnableEncryptionData(environment);
    }
}

Aes加密代码

java 复制代码
package com.xxx.util.encrypt;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;

/**
 * @author HanKeQi
 * @date 2022/10/30
 */
@Slf4j
public class AesUtils {

    public static final String IV = "vKapxbKpyptKkwuP";

    private static final String P_KCS5_PADDING="AES/CBC/PKCS5Padding";

    private static final String KEY = "AES";

    public static final String P_KEY = "6U7Si019ireqa7vAscWBkbPClOYtn6gb";


    /**
     * @param content base64处理过的字符串
     * @param pkey    密匙
     * @return String    返回类型
     * @throws Exception
     * @throws
     * @Title: aesDecodeStr
     * @Description: 解密 失败将返回NULL
     */
    public static String decodeStr(String content, String pkey) throws Exception {
        try {
            log.info("待解密内容: {}", content);
            byte[] base64DecodeStr = Base64.decodeBase64(content);
            byte[] aesDecode = decode(base64DecodeStr, pkey);
            if (aesDecode == null) {
                return null;
            }
            String result;
            result = new String(aesDecode, "UTF-8");
            return result;
        } catch (Exception e) {
            throw new Exception("解密异常");
        }
    }
    /**
     * 解密 128位
     *
     * @param content 解密前的byte数组
     * @param pkey    密匙
     * @return result  解密后的byte数组
     * @throws Exception
     */
    public static byte[] decode(byte[] content, String pkey,String IV) throws Exception {

        SecretKeySpec skey = new SecretKeySpec(pkey.getBytes(),  KEY);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));
        //创建密码器
        Cipher cipher = Cipher.getInstance(P_KCS5_PADDING);
        //初始化解密器
        cipher.init(Cipher.DECRYPT_MODE, skey, iv);
        byte[] result = cipher.doFinal(content);
        // 解密
        return result;
    }

    public static byte[] decode(byte[] content, String pkey) throws Exception {
        return decode(content,pkey,IV);
    }

    /**
     * @param content 加密前原内容
     * @param pkey    长度为16个字符,128位
     * @return base64EncodeStr   aes加密完成后内容
     * @throws
     * @Title: aesEncryptStr
     * @Description: aes对称加密
     */
    public static String encryptStr(String content, String pkey) {
        byte[] aesEncrypt = encrypt(content, pkey);
        String base64EncodeStr = Base64.encodeBase64String(aesEncrypt);
        return base64EncodeStr;
    }


    /**
     * 加密 128位
     *
     * @param content 需要加密的原内容
     * @param pkey    密匙
     * @return
     */
    public static byte[] encrypt(String content, String pkey, String iv) {
        try {
            //SecretKey secretKey = generateKey(pkey);
            //byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec skey = new SecretKeySpec(pkey.getBytes(), KEY);
            Cipher cipher = Cipher.getInstance(P_KCS5_PADDING);// "算法/加密/填充"
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, skey, ivParameterSpec);//初始化加密器
            byte[] encrypted = cipher.doFinal(content.getBytes("UTF-8"));
            return encrypted; // 加密
        } catch (Exception e) {
            log.info("encrypt() method error:", e);
        }
        return null;
    }
    public static byte[] encrypt(String content, String pkey) {
        return encrypt(content,pkey, IV);
    }


}

配置文件

yaml 复制代码
spring:
  redis:
    database: 1
    host: redis.commons.svc.cluster.local
    port: 6379
    # 使用了 AesUtils.encryptStr("ADoZH2Gw6KEw51c3Mk", P_KEY);
    password: ENC(hji+7pHQpX0f0/dVncyT/leJ6sWHiCUlFq7LdDJjo1s=)
相关推荐
砍材农夫11 分钟前
物联网实战|Spring Boot MQTT平台 |emqx broker实战
spring boot·spring·spring cloud·mybatis
似璟如你23 分钟前
Java 开发者的 Go 语法基础:从 0 开始快速上手 Go
java·开发语言·后端·golang·go·编程语言
zzz_236838 分钟前
TencentDB-Agent-Memory 深度解析:让多个 Agent 共享项目经验的记忆中枢
java·开发语言·jvm·人工智能·agent·memory·tencent db
vx-程序开发1 小时前
django医院预约挂号系统---附源码23353
java·javascript·spring boot·python·eclipse·django·php
金斗潼关1 小时前
ysoserial的使用
java
ruleslol1 小时前
volatile 关键字
java
Codelinghu2 小时前
AI 写代码越强,程序员越不能只懂代码
后端
卡卡敲码2 小时前
Skills 撞车了,Agent 怎么选
后端
羑悻2 小时前
周一早上三件事砸过来,我以为要延期,结果 AI 替我扛了一半!
后端
文艺理科生2 小时前
3 年,8 种方案,1 次重构:LangChain 记忆方案如何从混乱走向清晰
前端·后端·架构