开发中,公司会要求对敏感字段进行加密处理后入库,查询的时候需要解密后展示,这就要求原字符串和加密字符串之间进行转换
如果一两个字符串还好,可以直接在入库的时候和查询的时候处理一下,但是如果有很多字段都需要这样处理怎么办?
Mybatis里面有一个TypeHandler可以解决这个问题,只需要在需要加密/解密的字段上使用@TableField(typeHandler = AesTypeHandler.class),
包含该字段的实体上使用@TableName(autoResultMap = true)即可(PS:AesTypeHandler是自定义的TypeHandler)
为了方便,这里我们使用的是Hutool的AES加密工具
首先导入依赖
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.8</version> </dependency>
然后创建AesUtil加密工具
package com.qjc.utils; import cn.hutool.core.util.HexUtil; import cn.hutool.crypto.SecureUtil; import org.apache.commons.lang3.StringUtils; public class AESUtil { private static final String AES_KEY = "AES_KEY"; private static final byte[] KEY_BYTES; private static String keyStr = "ad1725339b2dd0a68903c57b635942ca"; static { KEY_BYTES = new byte[16]; int i = 0; for (byte b : keyStr.getBytes()) { KEY_BYTES[i++ % 16] ^= b; } } public static String encrypt(String content) { if (StringUtils.isBlank(content)) { return content; } return HexUtil.encodeHexStr(SecureUtil.aes(KEY_BYTES).encrypt(content), false); } public static String decrypt(String content) { if (StringUtils.isBlank(content)) { return content; } return SecureUtil.aes(KEY_BYTES).decryptStr(content); } public static void main(String[] args) { String encrypted = encrypt("测试"); System.out.println(encrypted); System.out.println(decrypt(encrypted)); } }
定义AesTypeHandler
package com.qjc.config; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.qjc.utils.AESUtil; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** 数据库中的数据类型 */ @MappedJdbcTypes(JdbcType.VARCHAR) /** 处理后的数据类型 */ @MappedTypes(value = String.class) public class AesTypeHandler extends BaseTypeHandler { @Override public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, AESUtil.encrypt((String) parameter)); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return StringUtils.isBlank(rs.getString(columnName)) ? rs.getString(columnName) : AESUtil.decrypt(rs.getString(columnName)); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return StringUtils.isBlank(rs.getString(columnIndex)) ? rs.getString(columnIndex) : AESUtil.decrypt(rs.getString(columnIndex)); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return StringUtils.isBlank(cs.getString(columnIndex)) ? cs.getString(columnIndex) : AESUtil.decrypt(cs.getString(columnIndex)); } }
然后再实体和字段上添加注解
package com.qjc.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import java.time.LocalDateTime; import com.qjc.config.AesTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @TableName(value = "t_user", autoResultMap = true) public class TUser extends Model { private static final long serialVersionUID = 1L; @TableId("id") private Long id; @TableField(typeHandler = AesTypeHandler.class) private String name; private String address; private Integer age; private LocalDateTime createTime; private LocalDateTime updateTime; }
测试
@Test public void test() { TUser user = new TUser(); user.setName("用户"); user.setAge(18); user.setAddress("地址"); userMapper.insert(user); }
插入数据
查询数据
mysql中直接用HEX(AES_ENCRYPT(str,key_str))函数生成加密串就行,和工具AESUtil生成的加密串是一致的。mysql中解密AES字符串AES_DECRYPT(UNHEX(str),key_str)