Spring Boot 初级入门教程(二十) —— 配置文件密码信息自定义算法加密
2020年07月05日 21:17:16 SpringBoot ⁄ 共 8179字 暂无评论 ⁄ 被围观 3,338次

随着信息安全防护措施的提升,越来越多的项目要求项目中的密码不能有明文,都需要加密,配置文件中相关的密码也不例外,都需要进行加密处理后再配置。那如何对 SpringBoot 配置文件中的明文密码进行加密呢?这篇就以前面的数据源配置为例,对数据库用户对应的密码进行加密,加密方式为自定义算法加密。

这篇开始,由于自己也逐渐去学习并适应 IDEA 工具的开发,所以把项目工程从 STS 开发环境迁移到了 IDEA 开发环境。

第一步,创建加密工具类

既然是自定义算法加密,那首先需要有个自定义加密解密的方法,可以封装为工具类放到项目中,至于加密算法的复杂性,可以随项目要求定义,这里就拿个简单的加密方法做测试。由于没有对应的包,这里先建个工具类的包util,如图:

创建加密解密工具类 Base64Util.java,主要代码如下:

  1. package cn.menglanglang.test.springboot.util;  
  2.   
  3. import javax.crypto.Cipher;  
  4. import javax.crypto.SecretKey;  
  5. import javax.crypto.SecretKeyFactory;  
  6. import javax.crypto.spec.DESKeySpec;  
  7. import java.security.InvalidKeyException;  
  8. import java.security.NoSuchAlgorithmException;  
  9. import java.security.spec.InvalidKeySpecException;  
  10. import java.util.Collection;  
  11. import java.util.Map;  
  12.   
  13. /** 
  14.  * @author 孟郎郎 
  15.  * @version 1.0 
  16.  * @desc 基于 base64 编码加密解密字符串工具类 
  17.  * @blog http://www.menglanglang.cn 
  18.  * @date 2020/7/5 19:20 
  19.  */  
  20. public class EADcryptUtil {  
  21.   
  22.     private static final String DES_ALGORITHM = "DES";  
  23.     private static final String SECRET_KEY = "DEFAULT_KEY";  
  24.   
  25.     /** 
  26.      * DES默认密钥加密 
  27.      * 
  28.      * @param plainData 
  29.      * @return 
  30.      * @throws Exception 
  31.      */  
  32.     public static String encryptDES(String plainData) {  
  33.         return encryptDES(plainData, SECRET_KEY);  
  34.     }  
  35.   
  36.     /** 
  37.      * DES默认密钥解密 
  38.      * 
  39.      * @param secretData 
  40.      * @return 
  41.      * @throws Exception 
  42.      */  
  43.     public static String decryptDES(String secretData) {  
  44.         return decryptDES(secretData, SECRET_KEY);  
  45.     }  
  46.   
  47.     /** 
  48.      * DES指定密钥加密 
  49.      * 
  50.      * @param plainData 
  51.      * @param secretKey 
  52.      * @return 
  53.      * @throws Exception 
  54.      */  
  55.     public static String encryptDES(String plainData, String secretKey) {  
  56.         if (isObjNull(plainData)) {  
  57.             return "";  
  58.         }  
  59.         Cipher cipher = null;  
  60.         byte[] buf = null;  
  61.         try {  
  62.             cipher = Cipher.getInstance(DES_ALGORITHM);  
  63.             cipher.init(Cipher.ENCRYPT_MODE, generateKey(secretKey));  
  64.             buf = cipher.doFinal(plainData.getBytes());  
  65.         } catch (Exception e) {  
  66.             e.printStackTrace();  
  67.             return "";  
  68.         }  
  69.         return Base64Utils.encode(buf);  
  70.     }  
  71.   
  72.     /** 
  73.      * DES指定密钥解密 
  74.      * 
  75.      * @param secretData 
  76.      * @param secretKey 
  77.      * @return 
  78.      * @throws Exception 
  79.      */  
  80.     public static String decryptDES(String secretData, String secretKey) {  
  81.         if (isObjNull(secretData)) {  
  82.             return "";  
  83.         }  
  84.         Cipher cipher = null;  
  85.         byte[] buf = null;  
  86.         try {  
  87.             cipher = Cipher.getInstance(DES_ALGORITHM);  
  88.             cipher.init(Cipher.DECRYPT_MODE, generateKey(secretKey));  
  89.             buf = cipher.doFinal(Base64Utils.decode(secretData.toCharArray()));  
  90.         } catch (Exception e) {  
  91.             e.printStackTrace();  
  92.             return "";  
  93.         }  
  94.         return new String(buf);  
  95.     }  
  96.   
  97.     /** 
  98.      * 获得密钥 
  99.      * 
  100.      * @param secretKey 
  101.      * @return 
  102.      * @throws NoSuchAlgorithmException 
  103.      * @throws InvalidKeyException 
  104.      * @throws InvalidKeySpecException 
  105.      */  
  106.     private static SecretKey generateKey(String secretKey)  
  107.             throws NoSuchAlgorithmException, InvalidKeyException,  
  108.             InvalidKeySpecException {  
  109.         SecretKeyFactory keyFactory = SecretKeyFactory  
  110.                 .getInstance(DES_ALGORITHM);  
  111.         DESKeySpec keySpec = new DESKeySpec(secretKey.getBytes());  
  112.         keyFactory.generateSecret(keySpec);  
  113.         return keyFactory.generateSecret(keySpec);  
  114.     }  
  115.   
  116.     /** 
  117.      * 判断字符串是否为空,集合是否为空,数组是否为空 返回true为空 
  118.      */  
  119.     @SuppressWarnings("rawtypes")  
  120.     public static boolean isObjNull(Object obj) {  
  121.         if (obj == null)  
  122.             return true;  
  123.   
  124.         if (obj instanceof CharSequence)  
  125.             return ((CharSequence) obj).length() == 0;  
  126.   
  127.         if (obj instanceof Collection)  
  128.             return ((Collection) obj).isEmpty();  
  129.   
  130.         if (obj instanceof Map)  
  131.             return ((Map) obj).isEmpty();  
  132.   
  133.         if (obj instanceof Object[]) {  
  134.             Object[] object = (Object[]) obj;  
  135.             if (object.length == 0) {  
  136.                 return true;  
  137.             }  
  138.             boolean empty = true;  
  139.             for (int i = 0; i < object.length; i++) {  
  140.                 if (!isObjNull(object[i])) {  
  141.                     empty = false;  
  142.                     break;  
  143.                 }  
  144.             }  
  145.             return empty;  
  146.         }  
  147.         return false;  
  148.     }  
  149.   
  150.     static class Base64Utils {  
  151.   
  152.         static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="  
  153.                 .toCharArray();  
  154.         static private byte[] codes = new byte[256];  
  155.         static {  
  156.             for (int i = 0; i < 256; i++)  
  157.                 codes[i] = -1;  
  158.             for (int i = 'A'; i <= 'Z'; i++)  
  159.                 codes[i] = (byte) (i - 'A');  
  160.             for (int i = 'a'; i <= 'z'; i++)  
  161.                 codes[i] = (byte) (26 + i - 'a');  
  162.             for (int i = '0'; i <= '9'; i++)  
  163.                 codes[i] = (byte) (52 + i - '0');  
  164.             codes['+'] = 62;  
  165.             codes['/'] = 63;  
  166.         }  
  167.   
  168.         /** 
  169.          * 将原始数据编码为base64编码 
  170.          */  
  171.         static public String encode(byte[] data) {  
  172.             char[] out = new char[((data.length + 2) / 3) * 4];  
  173.             for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {  
  174.                 boolean quad = false;  
  175.                 boolean trip = false;  
  176.                 int val = (0xFF & (int) data[i]);  
  177.                 val <<= 8;  
  178.                 if ((i + 1) < data.length) {  
  179.                     val |= (0xFF & (int) data[i + 1]);  
  180.                     trip = true;  
  181.                 }  
  182.                 val <<= 8;  
  183.                 if ((i + 2) < data.length) {  
  184.                     val |= (0xFF & (int) data[i + 2]);  
  185.                     quad = true;  
  186.                 }  
  187.                 out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];  
  188.                 val >>= 6;  
  189.                 out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];  
  190.                 val >>= 6;  
  191.                 out[index + 1] = alphabet[val & 0x3F];  
  192.                 val >>= 6;  
  193.                 out[index + 0] = alphabet[val & 0x3F];  
  194.             }  
  195.   
  196.             return new String(out);  
  197.         }  
  198.   
  199.         /** 
  200.          * 将base64编码的数据解码成原始数据 
  201.          */  
  202.         static public byte[] decode(char[] data) {  
  203.             int len = ((data.length + 3) / 4) * 3;  
  204.             if (data.length > 0 && data[data.length - 1] == '=')  
  205.                 --len;  
  206.             if (data.length > 1 && data[data.length - 2] == '=')  
  207.                 --len;  
  208.             byte[] out = new byte[len];  
  209.             int shift = 0;  
  210.             int accum = 0;  
  211.             int index = 0;  
  212.             for (int ix = 0; ix < data.length; ix++) {  
  213.                 int value = codes[data[ix] & 0xFF];  
  214.                 if (value >= 0) {  
  215.                     accum <<= 6;  
  216.                     shift += 6;  
  217.                     accum |= value;  
  218.                     if (shift >= 8) {  
  219.                         shift -= 8;  
  220.                         out[index++] = (byte) ((accum >> shift) & 0xff);  
  221.                     }  
  222.                 }  
  223.             }  
  224.             if (index != out.length)  
  225.                 throw new Error("miscalculated data length!");  
  226.             return out;  
  227.         }  
  228.     }  
  229.   
  230. }  

第二步:测试加密方法正确性

使用工具类中的加密解密方法,测试加密后的密串,能否被解密函数正常解析。

  1. package cn.menglanglang.test.springboot;  
  2.   
  3. import cn.menglanglang.test.springboot.util.EADcryptUtil;  
  4. import org.junit.Test;  
  5.   
  6. /** 
  7.  * @author 孟郎郎 
  8.  * @version 1.0 
  9.  * @desc 
  10.  * @blog http://www.menglanglang.cn 
  11.  * @date 2020/6/17 22:45 
  12.  */  
  13. public class TestMethod {  
  14.   
  15.     @Test  
  16.     public void test() {  
  17.         System.out.println("123456加密后密码串为:" + EADcryptUtil.encryptDES("123456"));  
  18.         System.out.println("123456解密后密码串为:" + EADcryptUtil.decryptDES("QscA0onvWKA="));  
  19.     }  
  20.   
  21. }  

输出结果为:

第三步:修改原明文密码配置

用测试时得到的加密串,替换原明文密码,如下图所示。

替换为如下图所示,注意在实际开发中,把配置文件中的明文密码部分删除掉,不然加密白做了!!!

第四步:修改密码设值部分

在上一篇配置多数据源的文章中,提到了配置多数据源的类 FirstDataSourceConfig 和 SecondDataSourceConfig,分别修改类中密码部分如下:

第五步:启动项目测试

重新启动项目,测试是否能够连上数据库,页面查询数据是否正常。

到此,通过自定义算法加密数据库密码大功告成。

原文链接:https://blog.csdn.net/tzhuwb/article/details/106818510

给我留言

留言无头像?