Rya*_*yan 8 java mysql encryption hibernate jpa
我需要加密 MySQL 数据库表中的值:
用户
| userId | email | userAge | firstName| lastName | userType |
|--------|--------------|---------|-----------|----------|--------- |
| 1 |john@gmail.com| 20 | John | Smith | 1 |
Run Code Online (Sandbox Code Playgroud)
我的用户类别如下
@Entity
@Table(name = "user")
public class User{
@Id @GeneratedValue
@Column(name = "userId ")
private int userId;
@Column(name = "firstName")
private String firstName;
@Column(name = "email")
private String email;
@Column(name = "lastName")
private String lastName;
@Column(name = "userType ")
private String userType ;
// getters and setters
}
Run Code Online (Sandbox Code Playgroud)
我尝试使用 AttributeConverter 来做到这一点
@Component
public class ValueAttributeConverter implements AttributeConverter<String, String> {
private static final String AES = "AES";
private static final String SECRET = "secretkey";
private final Key key;
private final Cipher cipher;
public AttributeEncryptor() throws Exception {
key = new SecretKeySpec(SECRET.getBytes(), AES);
cipher = Cipher.getInstance(AES);
}
@Override
public String convertToDatabaseColumn(String value) {
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
return Base64.getEncoder().encodeToString(cipher.doFinal(value.getBytes()));
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException e)
{
throw new IllegalStateException(e);
}
}
@Override
public String convertToEntityAttribute(String value) {
try {
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(Base64.getDecoder().decode(value)));
} catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException e{
throw new IllegalStateException(e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
并在属性上添加@Convert注解
@Column
@Convert(converter = ValueAttributeConverter.class)
private String email;
Run Code Online (Sandbox Code Playgroud)
这将加密列值。
但问题是我在 UserRepository 中使用了本机查询
@Query(nativeQuery = true , value = "select * from users where email=?1
and
firstName =?2")
Run Code Online (Sandbox Code Playgroud)
在这种情况下,它不起作用,因为电子邮件值已加密。如果我使用其他列而不是电子邮件,例如姓氏。它正在工作并返回解密的值。
我尝试在查询中起诉字符串之前对其进行加密
email = valueAttributeConverter.convertToEntityAttribute(email);
Run Code Online (Sandbox Code Playgroud)
它有效,但我不知道这种方法是否好。
我也尝试过使用@ColumnTransformer
@Column
@ColumnTransformer(
read = "cast(aes_decrypt(email, 'secretkey') as char(255))",
write = "aes_encrypt(?, 'secretkey')"
)
private String email;
Run Code Online (Sandbox Code Playgroud)
这在加密时也工作正常,但在我需要解密时就不起作用。即使我选择使用另一列
@Query(nativeQuery = true , value = "select * from users where userId
=?1")
Run Code Online (Sandbox Code Playgroud)
它不会解密该值,而是返回加密的值。
我的问题是,是否有更好的方法可以解决此加密和解密问题,并在 JPA 和 nativeQuery 中使用它?
我认为您应该重新考虑在代码中使用本机查询。您可以查看使用数据访问对象模式:https ://www.baeldung.com/java-dao-pattern
使用本机查询应该是最后的手段,并且仅在您绝对需要某些特定于平台的功能的情况下使用。
从架构上讲,您可以保持 User 实体不变,但在数据访问对象中用本机查询替换JPQL查询,例如本机查询示例
@Query(nativeQuery = true , value = "select * from users where userId =?1")
Run Code Online (Sandbox Code Playgroud)
将转换为 DAO 方法:
@Query(nativeQuery = true , value = "select * from users where userId =?1")
Run Code Online (Sandbox Code Playgroud)
DAO 模式允许您使用业务逻辑创建任意复杂的查询(就像您的情况一样),并为您提供更多控制。如果您使用示例中的 AttributeConverter,JPA 应该在返回的 User 对象中自动处理加密值。
JPQL 的优点在于它不是本机 SQL,而是由 JPA 解释,然后自动生成特定于平台的查询。您的代码可以在 JPA 支持的任何数据库后端上运行。此外,您还可以免费获得 SQL 注入保护等安全优势。
| 归档时间: |
|
| 查看次数: |
6399 次 |
| 最近记录: |