.项目中我们存储一些用户信息的使用后根据规定,不可以存储明文,尤其是密码,实现的办法有好多种,今天承接上一篇文章mybatis拦截器,利用拦截器实现使用注解的方式在数据插入前进行加密,查询是自动进行解密的功能,前面提到过mybatis-plus拦截器用起来更方便一点,但是有个问题就是,如果使用了mybatis-plus拦截器就没办法在换其他的框架了
此功能是根据自己需求改造其他大佬的项目而来(以下链接是原项目),目前仅用于自己测试没有问题,未经实际环境验证,请大家斟酌使用! mybatis-plus其实也支持此功能,但是他是收费项
https://blog.csdn.net/weixin_43655425/article/details/121394246
与原项目不同的是增加了对非对称加密算法的支持, 目前仅在里面实现的SM2,SM3,SM4三中算法,理论上加上非对称加密算法后应该是支持绝大多数算法,可根据需求直接更改源代码或实现ICrypto接口自定义
里面的encrypt是实现加密注解的源代码,encrypt_demo为加密注解的演示demo
https://cowtransfer.com/s/f683e7cf5e9143
增加配置项,目前的配置是支持国密SM2,SM3,SM4,如果不配置,将使用默认配置进行加密,对于密钥对的生成,提供了GenerateKeyPair工具类生成密钥对
- #加密注解配置,如果不配置将使用默认配置加密
- privacy:
- crypto:
- #密钥,用于SM4对称加密,随机16位字符串即可
- key: qwerdhdhfgcbshur
- #私钥公钥,用于SM2费对称加密,可用测试类中的方法生成替换
- privateKey: 308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420699d3f230b7ab5fe4520b550fb021585b648950ba1ec988a0730fa95fa809f26a00a06082a811ccf5501822da1440342000487a23a1bde2da2d7004dbfc9101aa30042880593108e99d7b47c72c139abe8159174dcac41c998b818ff9cec508fb9a732dbbd1f957d8fc423c164d42bb3d04c
- publicKey: 3059301306072a8648ce3d020106082a811ccf5501822d0342000487a23a1bde2da2d7004dbfc9101aa30042880593108e99d7b47c72c139abe8159174dcac41c998b818ff9cec508fb9a732dbbd1f957d8fc423c164d42bb3d04c
- /**
- * 生成SM2非对称加密算法的密钥对,可用于替换yml配置文件中的 privateKey 和 publicKey
- *
- * @author zzt
- * @version 1.0.0
- * @date 2022/8/5 16:15
- */
- public class GenerateKeyPair {
-
- public static void main(String[] args) {
- KeyPair pair = SecureUtil.generateKeyPair("SM2");
- byte[] privateKey = pair.getPrivate().getEncoded();
- byte[] publicKey = pair.getPublic().getEncoded();
- String privateKeyStr = HexUtil.encodeHexStr(privateKey);
- String publicKeyStr = HexUtil.encodeHexStr(publicKey);
- System.out.println("privateKey: " + privateKeyStr);
- System.out.println("publicKey: " + publicKeyStr);
- }
- }
直接将注解添加到需要加密的字段上即可,其中注解中有三个参数需要注意含义:
key:是对插加密的密钥16位字符串即可,该项如果自定义进行了配置,当解密时需要使用相同的密钥否则无法解密
algorithm: 选择加密算法类型
iCrypto:加密实现类,当默认算法不满足是可自定义算法加密类
- /**
- * 用户信息
- *
- * @author zzt
- * @version 1.0.0
- * @date 2022/8/4 11:02
- */
- @TableName("encrypt_demo")
- @Data
- @Accessors(chain = true)
- public class EncryptDemoEntity {
-
- @TableId
- private Long id;
-
- /**
- * 指定SM2,非对称加密算法,该算法需要配置公钥和私钥,可在配置文件中配置
- */
- @FieldEncrypt(algorithm = Algorithm.SM2)
- @TableField(value = "USER_NAME")
- private String userName;
-
- /**
- * 使用默认的SM4加密算法,该算法可以被解密
- */
- @FieldEncrypt
- @TableField(value = "PHONE_NUM")
- private String phoneNum;
-
- /**
- * 使用自定义SM3算法,该算法不可以被解密,查询时将返回密文
- */
- @FieldEncrypt(algorithm = Algorithm.SM3)
- @TableField(value = "PASS_WORD")
- private String passWord;
- }
- @SpringBootTest
- @RunWith(SpringRunner.class)
- class EncryptDemoApplicationTests {
-
- @Autowired
- private EncryptDemoMapper encryptDemoMapper;
-
- /**
- * 一般情况下使用默认SM4算法和指定SM3算法,SM2算法加密
- */
- @Test
- public void encryptTest1() {
- EncryptDemoEntity entity = new EncryptDemoEntity();
- Long id = System.currentTimeMillis();
- entity.setId(id)
- .setPhoneNum("15555555555")
- .setUserName("admin")
- .setPassWord("111111");
- encryptDemoMapper.insert(entity);
- System.out.println("加密后的结果: " + entity);
- //加密后的结果: EncryptDemoEntity(id=1659596682578, userName=040EA7241AF8C0FA5F8816B3F6DBFC6A02CFF32BE7EE8EEF741183E64267DACC6773478A97D8CB8B60FFA9D3F4B691F2B96F5EB607A7995336FCB3CF5AA635E6EE58085EE9FDA5F7EBA29F7968E8FF6D47D3A111712E69801489EDE0D3F42F507322F09A1154, phoneNum=90cd9092b5c643ef966346ce1e3ad224, passWord=c7f66beee198fb411c8623e53cbbc6eb1e0f078b5d68ed7f10d02ffb0af46d44)
- entity = encryptDemoMapper.selectById(id);
- System.out.println("解密后的结果: " + entity);
- //password字段使用的是SM3算法加密,不可被解密,所以返回的是密文
- //解密后的结果: EncryptDemoEntity(id=1659596682578, userName=admin, phoneNum=15555555555, passWord=c7f66beee198fb411c8623e53cbbc6eb1e0f078b5d68ed7f10d02ffb0af46d44)
- }
-
- /**
- * 给SM4对称加密算法指定自定义密钥
- */
- @Test
- public void encryptTest2() {
- EncryptDemoVo vo = new EncryptDemoVo();
- Long id = System.currentTimeMillis();
- vo.setId(id)
- .setUserName("root")
- .setPhoneNum("15777777777")
- .setPassWord("222222");
- //如果把vo的数据复制到entity,vo的加密配置将会被entity覆盖,需要注意
- encryptDemoMapper.insertVo(vo);
- System.out.println("加密后的结果: " + vo);
- //加密后的结果: EncryptDemoVo(id=1659597730091, userName=043E4074164748F73C108368A3C9017FE5396B807743CA536603FD1990584FC1A02ADADF23FBCD508B62788712CD85CF145248086E6D7A873E002B07405E9D0D2618C097D237445A4F8641368EA75257A916C77007F61424D966D574EB199F37AB1A4C54DD, phoneNum=8a089016eaba292348b6c81aeb170a00, passWord=8b30ba1c30168d83a5ef274f7b27f9aea4cda203ca0fc8965c1c5316dfb20309)
- vo = encryptDemoMapper.selectVoById(id);
- System.out.println("使用自定义密钥解密后的结果: " + vo);
- //使用自定义密钥解密后的结果: EncryptDemoVo(id=1659597730091, userName=root, phoneNum=15777777777, passWord=8b30ba1c30168d83a5ef274f7b27f9aea4cda203ca0fc8965c1c5316dfb20309)
- EncryptDemoTwoVo encryptDemoTwoVo = encryptDemoMapper.selectEncryptTwoVo(id);
- System.out.println("使用默认密钥解密后的结果: " + encryptDemoTwoVo);
- //注意这里EncryptDemoTwoVo里面的phoneNum使用的是默认密钥,但是这条数据我们使用的是自定义密钥加密的,所以解密结果是无法成功的,会报 BadPaddingException: pad block corrupted的异常信息!
- //使用默认密钥解密后的结果: EncryptDemoTwoVo(id=1659598162187, userName=root, phoneNum=8a089016eaba292348b6c81aeb170a00, passWord=8b30ba1c30168d83a5ef274f7b27f9aea4cda203ca0fc8965c1c5316dfb20309)
- }
-
-
- /**
- * 生成SM2非对称加密算法的密钥对,可用于替换yml配置文件中的 privateKey 和 publicKey
- */
- @Test
- public void generateKeyPair() {
- KeyPair pair = SecureUtil.generateKeyPair("SM2");
- byte[] privateKey = pair.getPrivate().getEncoded();
- byte[] publicKey = pair.getPublic().getEncoded();
- String privateKeyStr = HexUtil.encodeHexStr(privateKey);
- String publicKeyStr = HexUtil.encodeHexStr(publicKey);
- System.out.println("privateKey: " + privateKeyStr);
- System.out.println("publicKey: " + publicKeyStr);
- }
- }
如有发现什么不足或可以改进的地方,欢迎指正讨论