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=)
相关推荐
希忘auto1 分钟前
详解MySQL安装
java·mysql
冰淇淋烤布蕾12 分钟前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺19 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE35 分钟前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)43 分钟前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
ApiHug2 小时前
ApiSmart x Qwen2.5-Coder 开源旗舰编程模型媲美 GPT-4o, ApiSmart 实测!
人工智能·spring boot·spring·ai编程·apihug
魔道不误砍柴功2 小时前
探秘Spring Boot中的@Conditional注解
数据库·spring boot·oracle
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端