SpringBoot+MyBatis实现数据库字段加密
今天分享一篇基于SpringBoot+MyBatis来实现数据库字段加密的操作,喜欢的朋友可以借鉴
大致的实现流程
业务层-->系统拦截器-->数据库-->系统拦截器-->返回结果
加密注解设计
把需要加密的字段通过我们自定义的加密注解进行标识,所以我们需要先自定义一段加密注解的代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
}
实体类
在实体类上使用注解标记需要加密字段
@Data
public class User {
private Long id;
private String username;
@Encrypt
private String password;
@Encrypt
private String email;
@Encrypt
private String phone;
}
加密工具类
基于AES加密算法实现对字段名的加密,大家可以选择其他的加密算法
public class EncryptionUtil {
privatestaticfinal String ALGORITHM = "AES";
privatestaticfinal String TRANSFORMATION = "AES/ECB/PKCS5Padding";
// AES加密
public static String encrypt(String plainText, String key) {
try {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
thrownew RuntimeException("加密失败", e);
}
}
// AES解密
public static String decrypt(String cipherText, String key) {
try {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
returnnew String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
thrownew RuntimeException("解密失败", e);
}
}
}
系统拦截器设计
通过拦截实现自动加密和自动解密
// 加密拦截器
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
public class FieldEncryptionInterceptor implements Interceptor {
@Value("${encryption.key:mySecretKey12345}")
private String encryptionKey;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement mappedStatement = (MappedStatement) args[0];
Object parameter = args[1];
// 获取SQL命令类型
String sqlCommandType = mappedStatement.getSqlCommandType().toString();
// 对INSERT和UPDATE操作进行加密处理
if ("INSERT".equals(sqlCommandType) || "UPDATE".equals(sqlCommandType)) {
encryptFields(parameter);
}
return invocation.proceed();
}
// 解密拦截器
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Component
public class FieldDecryptionInterceptor implements Interceptor {
@Value("${encryption.key:mySecretKey12345}")
private String encryptionKey;
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 执行原始方法
Object result = invocation.proceed();
// 对查询结果进行解密处理
if (result instanceof List) {
List<?> list = (List<?>) result;
for (Object item : list) {
decryptFields(item);
}
} else {
decryptFields(result);
}
return result;
}
}
}
测试场景
用户信息保护:在用户注册时,自动加密用户的密码、邮箱、手机号等敏感信息,即使数据库泄露也不会造成用户隐私泄露
金融数据保护:对用户的银行卡号、交易记录等金融数据进行加密存储,满足金融行业的合规要求
医疗医保数据保护:对患者的病历、诊断结果等医疗隐私数据进行加密,保护患者隐私
企业数据保护:对企业内部的商业机密、客户资料等重要数据进行加密保护
注意事项
虽然字段级加密功能强大,但在生产环境中使用时必须注意安全性:
密钥管理:不要在代码中硬编码密钥,应使用专业的密钥管理系统
算法选择:使用经过验证的加密算法,如AES-256
性能优化:合理选择需要加密的字段,避免对所有字段都进行加密
审计日志:记录所有加密解密操作,便于安全审计
定期轮换:定期更换加密密钥,降低密钥泄露风险

浙公网安备 33010602011771号