springboot配置文件属性加密

注:网上没有找到除了使用jasypt-spring-boot的其他简单使用方法,这里借鉴jasypt提供思路了一种思路,springboot 2.2.0之前和之后版本做法有点差异

配置文件

password: Enc[4SHQhZM1rmcHQ+X+gryPMw==]
decrypt:
  prefix: Enc[
  suffix: ]
  key: 12345678

加解密类

import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;
import java.security.SecureRandom;

public class DecryptUtil {

    private static final String CHARSET = "utf-8";
    private static final String ALGORITHM = "AES";
    private static final String RANDOM_ALGORITHM = "SHA1PRNG";

    public static String aesEncrypt(String content, String key) {

        if (content == null || key == null) {
            return null;
        }
        Key secretKey = getKey(key);
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] p = content.getBytes(CHARSET);
            byte[] result = cipher.doFinal(p);
            BASE64Encoder encoder = new BASE64Encoder();
            String encoded = encoder.encode(result);
            return encoded;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String aesDecrypt(String content, String key) {
        Key secretKey = getKey(key);
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] c = decoder.decodeBuffer(content);
            byte[] result = cipher.doFinal(c);
            String plainText = new String(result, CHARSET);
            return plainText;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static Key getKey(String key) {
        if (StringUtils.isEmpty(key)) {
            key = "12345678";// 默认key
        }
        try {
            SecureRandom secureRandom = SecureRandom.getInstance(RANDOM_ALGORITHM);
            secureRandom.setSeed(key.getBytes());
            KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
            generator.init(secureRandom);
            return generator.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        String newUserName= aesEncrypt("root","");
        System.out.println(newUserName);
    }

}

修改属性的bean文件

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.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.stream.StreamSupport;

import static java.util.stream.Collectors.toList;

@Component
public class DecryptConfig implements EnvironmentAware, BeanFactoryPostProcessor{

    private ConfigurableEnvironment environment;
    private String decryptPrefix = "Enc[";                      // 解密前缀标志 默认值
    private String decryptSuffix = "]";                         // 解密后缀标志 默认值
    private String decryptKey = "12345678";                     // 解密可以 默认值

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        MutablePropertySources propSources = environment.getPropertySources();
        StreamSupport.stream(propSources.spliterator(), false)
                .filter(ps -> ps instanceof OriginTrackedMapPropertySource)
                .collect(toList())
                .forEach(ps -> convertPropertySource(ps));
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;
    }

    private void convertPropertySource(PropertySource ps) {
        final Map source = (Map) ps.getSource();
        setDecryptProperties(source);
        source.forEach((k,v) -> {
            String value = String.valueOf(v);
            if (!value.startsWith(decryptPrefix) || !value.endsWith(decryptSuffix)) {
                return;
            }

            String cipherText = value.replace(decryptPrefix, "").replace(decryptSuffix, "");
            String clearText = DecryptUtil.aesDecrypt(cipherText, decryptKey);
            if(source.getClass().toString().endsWith("java.util.Collections$UnmodifiableMap")){
                //springboot 2.2.0之后
                update(source, k, clearText);
            }else{
                //springboot 2.2.0之前
                source.put(k, clearText);
            }
        });
    }

    private void update(Map source,Object key,String value){
        try{
            Field field = source.getClass().getDeclaredField("m");
            field.setAccessible(true);
            Map map = (Map) field.get(source);
            map.put(key,value);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    private void setDecryptProperties(Map source) {
        decryptPrefix = source.get("decrypt.prefix") == null ? decryptPrefix : String.valueOf(source.get("decrypt.prefix"));
        decryptSuffix = source.get("decrypt.suffix") == null ? decryptSuffix : String.valueOf(source.get("decrypt.suffix"));
        decryptKey = source.get("decrypt.key") == null ? decryptKey : String.valueOf(source.get("decrypt.key"));
    }
}

yaml属性自动加密

@Component
public class EncryptRunner implements CommandLineRunner {

    /**
     * 文件路径
     */
    private final String path = "/src/main/resources";

    /**
     * 文件名称
     */
    private final String prefix = "application";

    /**
     * 要加密的属性字段
     */
    private final Set<String> propSets = new HashSet<>(Arrays.asList(
            "password"
    ));

    @Autowired
    private DecryptConfig decryptConfig;

    @Override
    public void run(String... args) throws Exception {
        String userDir = System.getProperty("user.dir");
        File dir = new File(userDir + File.separator + path);
        //文件存在则加密
        if(dir.exists()){
            File[] files = dir.listFiles();
            for(File file : files){
                String name = file.getName();
                if (name != null && name.startsWith(prefix)) {
                    encrypt(file);
                }
            }
        }
    }

    /**
     * 加密
     */
    protected void encrypt(File file){
        StringBuilder sb = new StringBuilder();
        AtomicBoolean isUpdate = new AtomicBoolean(false);

        List<String> list = FileUtil.readLines(file , "UTF-8");
        if(list != null && list.size() > 0){
            list.stream().forEach(line -> {
                String split = ": ";
                int index = line.indexOf(split);

                boolean isNote = line.replace(" ", "").startsWith("#");
                if(!isNote && index > -1 && index + split.length() < line.length()){
                    String data1 = line.substring(0, index);
                    String data2 = line.substring(index + split.length());

                    boolean flag = propSets.stream().anyMatch(prop -> data1.contains(prop));
                    if(flag && StringUtils.isNotEmpty(data2) &&
                            !data2.startsWith(decryptConfig.getDecryptPrefix())){
                        String encrypt = DecryptUtils.aesEncrypt(data2, decryptConfig.getDecryptKey());
                        sb.append(data1);
                        sb.append(split);
                        sb.append(decryptConfig.getDecryptPrefix());
                        sb.append(encrypt);
                        sb.append(decryptConfig.getDecryptSuffix());

                        isUpdate.set(true);
                    }else{
                        sb.append(line);
                    }
                }else{
                    sb.append(line);
                }

                //根据操作系统识别换行符
                sb.append(System.getProperty("line.separator"));
            });
        }

        if(isUpdate.get()){
            FileUtil.writeString(sb.toString(), file, "UTF-8");
        }
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339