使用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工具类生成密钥对

#加密注解配置,如果不配置将使用默认配置加密
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);
    }
}

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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值