场景 : 数据存储到数据库时 , 除了密码 , 支付密码等敏感数据使用MD5等不可逆的方式加密外 , 其他的一些数据也需用到脱敏处理 , 如手机号 , 身份证号 , 银行卡号等 , 主要原因是当前登录用户或权限用户可能会用到此数据作为前端显示 , 此时需要使用对称加密的方式加密并解密 .
1.方式一
直接使用AES加密 , 解密 , 缺点是查询时需要遍历解密后传给前端
2.方式二
注解的方式加密解密 , 直接操作实体类
1.AES加密代码
public class AESUtil {
public static String decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
byte[] result = cipher.doFinal(content);
String jsonResult = Base64.getEncoder().encodeToString(result);
return jsonResult;
// 明文
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
public static String encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
// 128位的key生产者
//加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
// null。
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
String base64Result = Base64.getEncoder().encodeToString(result);
System.out.println(base64Result);
return base64Result;
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
}
2.对字段加密,解密的类
public class AESHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, AES.encrypt((String) parameter, SystemConstants.UserSalt));
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String columnValue = rs.getString(columnName);
return AES.decrypt(columnValue, SystemConstants.UserSalt);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String columnValue = rs.getString(columnIndex);
return AES.decrypt(columnValue, SystemConstants.UserSalt);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
String columnValue = cs.getString(columnIndex);
return AES.decrypt(columnValue, SystemConstants.UserSalt);
}
}
3.添加对应的注解 , 实体类添加注解
关键注解 : @TableName(value=“lb_user”,autoResultMap = true)
@TableField(value = “id_card”,typeHandler = AESHandler.class)
@data
@Accessors(chain = true)
@TableName(value="lb_user",autoResultMap = true)
@ApiModel(value = "LbUserEntity对象", description = "用户基本信息表")
public class LbUsersEntity implements Serializable {
@ApiModelProperty(value = "id")
@TableId(value = "id", type = IdType.AUTO)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@ApiModelProperty(value = "用户身份证号")
@TableField(value = "id_card",typeHandler = AESHandler.class)
private String idCard;
}