mybaits plus 字段加密与解密
- 写在前面
在我们实际开发中有的时候需要保证数据的安全,那么这个时候我们就需要对我们存储的数据加密,数据加密可以用很多方法实现,比如数据库加密,java代码加密和orm框架加密等等。
思考这么多加密方式我们应该选择那种方式?
1.数据库加密:主流数据库都提供了一系列的加密功能,如:AES_DECRYPT,DECODE等等
2.java代码: 通过java代码实现对字段的加密和解密
在这里我选择扩展mybaits plus框架实现加密
1.实现加密算法,这里我们选址aes对称加密算法,因为它是可逆算法。详情可参考AES加密算法的详细介绍与实现。 具体代码实现如下
package com.flow.utils;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* aes 加密的工具类
* 1.存储 加密的秘钥key
* 2.实现 aes 加密
* 3.实现aes解密的功能
*/
public class AES {
// 定义 aes 加密的key
// 密钥 必须是16位, 自定义,
// 如果不是16位, 则会出现InvalidKeyException: Illegal key size
// 解决方案有两种:
//1.需要安装Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files(可以在Oracle下载).
//2.设置设置key的长度为16个字母和数字的字符窜(128 Bit/8=16字符)就不报错了。
private static String key = "KEYJSDKKYHKLSSWS";
//定义加密的编码
private static String charset = "utf-8";
// 偏移量
private static int offset = 16;
private static String transformation = "AES/CBC/PKCS5Padding";
private static String algorithm = "AES";
/**
* 加密
*
* @param content
* @return
*/
public static String encrypt(String content) {
return encrypt(content, key);
}
/**
* 解密
*
* @param content
* @return
*/
public static String decrypt(String content) {
return decrypt(content, key);
}
/**
* 加密
*
* @param content 需要加密的内容
* @param key 加密密码
* @return
*/
public static String encrypt(String content, String key) {
try {
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
Cipher cipher = Cipher.getInstance(transformation);
byte[] byteContent = content.getBytes(charset);
cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化
byte[] result = cipher.doFinal(byteContent);
return new Base64().encodeToString(result); // 加密
} catch (Exception e) {
// LogUtil.exception(e);
}
return null;
}
/**
* AES(256)解密
*
* @param content 待解密内容
* @param key 解密密钥
* @return 解密之后
* @throws Exception
*/
public static String decrypt(String content, String key) {
try {
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, skey, iv);// 初始化
byte[] result = cipher.doFinal(new Base64().decode(content));
return new String(result); // 解密
} catch (Exception e) {
//LogUtil.exception(e);
}
return null;
}
}
- 扩展mybatis BaseTypeHandler 类 详解请看:mybatis中typehandler详解,具体实现代码如下:
package com.flow.types;
import com.flow.utils.AES;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class AesTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, AES.encrypt(parameter));
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return AES.decrypt(rs.getString(columnName));
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return AES.decrypt(rs.getString(columnIndex));
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return AES.decrypt(cs.getString(columnIndex));
}
}
- 最后通过mybaits plus @TableField使用该转换器代码如下:
@TableName(autoResultMap = true)
// @TableName 注解的 autoResultMap 一定要为true 否则查询得到的结果会为null
public class Estate extends BaseEntity<Long> {
private static final long serialVersionUID = 4470647135587698365L;
/**
* 物业公司的编号
*/
@TableElement(title = "物业编号")
@FormField(title = "物业编号", isSearch = true, isSubmit = false)
private String number;
/**
* 物业公司的名称
*/
@FormField(title = "物业公司名称", order = 1, isSearch = true, isSubmit = false)
@TableElement(title = "物业公司名称", order = 1)
@TableField(typeHandler = AesTypeHandler.class)
private String realEstateName;
/**
* 业主的姓名
*/
@FormField(title = "业主姓名", order = 2, isSearch = true, isSubmit = false)
@TableElement(title = "业主姓名", order = 2)
private String realName;
/**
* 业主身份证点好
*/
@TableElement(title = "业主身份证号码", order = 3)
@TableField(typeHandler = AesTypeHandler.class)
private String identity;
/**
* 业主的电话
*/
@TableElement(title = "业主电话号码", order = 4)
private String mobile;
/**
* 物业坐落
*/
@TableField(typeHandler = AesTypeHandler.class)
private String address;
/**
* 建筑面积
*/
private BigDecimal architecture;
/**
* 使用面积
*/
@TableField(value = "`use`")
private BigDecimal use;
/**
* 物业性质
*/
@EnumValue
private String nature;
}
- 测试结果
插入结果如下:
请求接口如下
友情提示:由于数据库存储的是加密后的结果,所以不能把加密字段当做模糊查询的条件字段,故谨慎使用。