• 使用mybatis拦截器实现字段加密解密


    前言

    .项目中我们存储一些用户信息的使用后根据规定,不可以存储明文,尤其是密码,实现的办法有好多种,今天承接上一篇文章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工具类生成密钥对

    1. #加密注解配置,如果不配置将使用默认配置加密
    2. privacy:
    3. crypto:
    4. #密钥,用于SM4对称加密,随机16位字符串即可
    5. key: qwerdhdhfgcbshur
    6. #私钥公钥,用于SM2费对称加密,可用测试类中的方法生成替换
    7. privateKey: 308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420699d3f230b7ab5fe4520b550fb021585b648950ba1ec988a0730fa95fa809f26a00a06082a811ccf5501822da1440342000487a23a1bde2da2d7004dbfc9101aa30042880593108e99d7b47c72c139abe8159174dcac41c998b818ff9cec508fb9a732dbbd1f957d8fc423c164d42bb3d04c
    8. publicKey: 3059301306072a8648ce3d020106082a811ccf5501822d0342000487a23a1bde2da2d7004dbfc9101aa30042880593108e99d7b47c72c139abe8159174dcac41c998b818ff9cec508fb9a732dbbd1f957d8fc423c164d42bb3d04c
    1. /**
    2. * 生成SM2非对称加密算法的密钥对,可用于替换yml配置文件中的 privateKey 和 publicKey
    3. *
    4. * @author zzt
    5. * @version 1.0.0
    6. * @date 2022/8/5 16:15
    7. */
    8. public class GenerateKeyPair {
    9. public static void main(String[] args) {
    10. KeyPair pair = SecureUtil.generateKeyPair("SM2");
    11. byte[] privateKey = pair.getPrivate().getEncoded();
    12. byte[] publicKey = pair.getPublic().getEncoded();
    13. String privateKeyStr = HexUtil.encodeHexStr(privateKey);
    14. String publicKeyStr = HexUtil.encodeHexStr(publicKey);
    15. System.out.println("privateKey: " + privateKeyStr);
    16. System.out.println("publicKey: " + publicKeyStr);
    17. }
    18. }

    用法

    直接将注解添加到需要加密的字段上即可,其中注解中有三个参数需要注意含义:

    key:是对插加密的密钥16位字符串即可,该项如果自定义进行了配置,当解密时需要使用相同的密钥否则无法解密

    algorithm: 选择加密算法类型

    iCrypto:加密实现类,当默认算法不满足是可自定义算法加密类

    1. /**
    2. * 用户信息
    3. *
    4. * @author zzt
    5. * @version 1.0.0
    6. * @date 2022/8/4 11:02
    7. */
    8. @TableName("encrypt_demo")
    9. @Data
    10. @Accessors(chain = true)
    11. public class EncryptDemoEntity {
    12. @TableId
    13. private Long id;
    14. /**
    15. * 指定SM2,非对称加密算法,该算法需要配置公钥和私钥,可在配置文件中配置
    16. */
    17. @FieldEncrypt(algorithm = Algorithm.SM2)
    18. @TableField(value = "USER_NAME")
    19. private String userName;
    20. /**
    21. * 使用默认的SM4加密算法,该算法可以被解密
    22. */
    23. @FieldEncrypt
    24. @TableField(value = "PHONE_NUM")
    25. private String phoneNum;
    26. /**
    27. * 使用自定义SM3算法,该算法不可以被解密,查询时将返回密文
    28. */
    29. @FieldEncrypt(algorithm = Algorithm.SM3)
    30. @TableField(value = "PASS_WORD")
    31. private String passWord;
    32. }

    测试方法及结果

    1. @SpringBootTest
    2. @RunWith(SpringRunner.class)
    3. class EncryptDemoApplicationTests {
    4. @Autowired
    5. private EncryptDemoMapper encryptDemoMapper;
    6. /**
    7. * 一般情况下使用默认SM4算法和指定SM3算法,SM2算法加密
    8. */
    9. @Test
    10. public void encryptTest1() {
    11. EncryptDemoEntity entity = new EncryptDemoEntity();
    12. Long id = System.currentTimeMillis();
    13. entity.setId(id)
    14. .setPhoneNum("15555555555")
    15. .setUserName("admin")
    16. .setPassWord("111111");
    17. encryptDemoMapper.insert(entity);
    18. System.out.println("加密后的结果: " + entity);
    19. //加密后的结果: EncryptDemoEntity(id=1659596682578, userName=040EA7241AF8C0FA5F8816B3F6DBFC6A02CFF32BE7EE8EEF741183E64267DACC6773478A97D8CB8B60FFA9D3F4B691F2B96F5EB607A7995336FCB3CF5AA635E6EE58085EE9FDA5F7EBA29F7968E8FF6D47D3A111712E69801489EDE0D3F42F507322F09A1154, phoneNum=90cd9092b5c643ef966346ce1e3ad224, passWord=c7f66beee198fb411c8623e53cbbc6eb1e0f078b5d68ed7f10d02ffb0af46d44)
    20. entity = encryptDemoMapper.selectById(id);
    21. System.out.println("解密后的结果: " + entity);
    22. //password字段使用的是SM3算法加密,不可被解密,所以返回的是密文
    23. //解密后的结果: EncryptDemoEntity(id=1659596682578, userName=admin, phoneNum=15555555555, passWord=c7f66beee198fb411c8623e53cbbc6eb1e0f078b5d68ed7f10d02ffb0af46d44)
    24. }
    25. /**
    26. * 给SM4对称加密算法指定自定义密钥
    27. */
    28. @Test
    29. public void encryptTest2() {
    30. EncryptDemoVo vo = new EncryptDemoVo();
    31. Long id = System.currentTimeMillis();
    32. vo.setId(id)
    33. .setUserName("root")
    34. .setPhoneNum("15777777777")
    35. .setPassWord("222222");
    36. //如果把vo的数据复制到entity,vo的加密配置将会被entity覆盖,需要注意
    37. encryptDemoMapper.insertVo(vo);
    38. System.out.println("加密后的结果: " + vo);
    39. //加密后的结果: EncryptDemoVo(id=1659597730091, userName=043E4074164748F73C108368A3C9017FE5396B807743CA536603FD1990584FC1A02ADADF23FBCD508B62788712CD85CF145248086E6D7A873E002B07405E9D0D2618C097D237445A4F8641368EA75257A916C77007F61424D966D574EB199F37AB1A4C54DD, phoneNum=8a089016eaba292348b6c81aeb170a00, passWord=8b30ba1c30168d83a5ef274f7b27f9aea4cda203ca0fc8965c1c5316dfb20309)
    40. vo = encryptDemoMapper.selectVoById(id);
    41. System.out.println("使用自定义密钥解密后的结果: " + vo);
    42. //使用自定义密钥解密后的结果: EncryptDemoVo(id=1659597730091, userName=root, phoneNum=15777777777, passWord=8b30ba1c30168d83a5ef274f7b27f9aea4cda203ca0fc8965c1c5316dfb20309)
    43. EncryptDemoTwoVo encryptDemoTwoVo = encryptDemoMapper.selectEncryptTwoVo(id);
    44. System.out.println("使用默认密钥解密后的结果: " + encryptDemoTwoVo);
    45. //注意这里EncryptDemoTwoVo里面的phoneNum使用的是默认密钥,但是这条数据我们使用的是自定义密钥加密的,所以解密结果是无法成功的,会报 BadPaddingException: pad block corrupted的异常信息!
    46. //使用默认密钥解密后的结果: EncryptDemoTwoVo(id=1659598162187, userName=root, phoneNum=8a089016eaba292348b6c81aeb170a00, passWord=8b30ba1c30168d83a5ef274f7b27f9aea4cda203ca0fc8965c1c5316dfb20309)
    47. }
    48. /**
    49. * 生成SM2非对称加密算法的密钥对,可用于替换yml配置文件中的 privateKey 和 publicKey
    50. */
    51. @Test
    52. public void generateKeyPair() {
    53. KeyPair pair = SecureUtil.generateKeyPair("SM2");
    54. byte[] privateKey = pair.getPrivate().getEncoded();
    55. byte[] publicKey = pair.getPublic().getEncoded();
    56. String privateKeyStr = HexUtil.encodeHexStr(privateKey);
    57. String publicKeyStr = HexUtil.encodeHexStr(publicKey);
    58. System.out.println("privateKey: " + privateKeyStr);
    59. System.out.println("publicKey: " + publicKeyStr);
    60. }
    61. }

    如有发现什么不足或可以改进的地方,欢迎指正讨论

  • 相关阅读:
    MySQL执行计划分析
    [WUSTCTF 2020]level2 脱壳
    Java发起Soap请求
    Javase.String 类
    Facebook宣布关闭面部识别系统,删除超过10亿用户的数据
    20年前,微软给金山那刀,现今一举将WPS推上领奖台,WPS,赢了
    【css面试题】实现2栏布局 右侧自适应; 3栏布局 中间自适应
    JAVA:实现Mandelbrot Mandelbrot曼德勃罗特集算法(附完整源码)
    【机器学习】决策树算法理论:算法原理、信息熵、信息增益、预剪枝、后剪枝、算法选择
    30 | 工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介
  • 原文地址:https://blog.csdn.net/winerpro/article/details/126208779