sam*_*gha 6 java encryption hibernate jpa interceptor
我正在为一个项目开发一些RESTFull Web服务.我使用Spring框架并使用gradle进行构建.问题是,我想在写入和读取数据时加密和解密数据表.我已经有了一个用AES等加密和解密数据的算法(类).我需要的是,如何注释这个方法来休眠实体类,我需要为这个类创建bean吗?
例如: -
@Column(columnDefinition= "LONGBLOB", name = "card_no")
@ColumnTransformer(
read="decrypt(card_no)",
write="encrypt(?)")
private String cardNo;
Run Code Online (Sandbox Code Playgroud)
像这样我想在这里添加我自己的加密/解密java方法.
Nar*_*ros 10
如果您可以访问JPA 2.1,我会主张使用@Convert带有AttributeConverter实现的注释.
一个AttributeConverter限定了一个实体属性的状态之间的合同,当它是序列化到数据存储,并且当它被从数据存储反序列化.
public class CreditCard {
@Convert(converter = CreditCardNumberConverter.class)
private String creditCardNumber;
}
Run Code Online (Sandbox Code Playgroud)
您的转换器实现可能如下所示
public class CreditCardNumberConverter implements AttributeConverter<String, String> {
@Override
public String convertToDatabaseColumn(String attribute) {
/* perform encryption here */
}
@Override
public String convertToEntityAttribute(String dbData) {
/* perform decryption here */
}
}
Run Code Online (Sandbox Code Playgroud)
如果你不能够利用JPA 2.1,一个EntityListener或使用@PrePersist,@PreUpdate以及@PostLoad可以用于加密和解密该数据库值执行类似的逻辑来使用.
请确保如果您决定使用一个EntityListener或任何Pre/Post回调方法注释,请将解密结果存储在瞬态字段中,并将该字段用作业务层的用法,如下所示:
public class CreditCard {
// this field could have package private get/set methods
@Column(name = "card_number", length = 25, nullable = false)
private String encrpytedCardNumber;
// this is the public operated upon field
@Transient
private String cardNumber;
@PostLoad
public void decryptCardNumber() {
// decrypts card number during DATABASE READ
this.cardNumber = EncryptionUtils.decrypt(encryptedCardNumber);
}
@PrePersist
@PreUpdate
public void encryptCardNumber() {
// encrypts card number during INSERT/UPDATE
this.encryptedCardNumber = EncryptionUtils.encrypt(cardNumber);
}
}
Run Code Online (Sandbox Code Playgroud)
执行上述操作可确保对象中的实体状态与数据库中存在的内容保持一致,而不会让Hibernate相信实体在加载数据库数据后立即更改.
你可以用几种方式做到这一点.
以下是一个简单的例子.请相应更改.
public class CustomListener{
@Inject
private EncryptorBean encryptor;
@PostLoad
@PostUpdate
public void decrypt(Object pc) {
if (!(pc instanceof)) {
return;
}
MyObj obj = (MyObj) pc;
if (obj.getCardNo() != null) {
obj.setCardNo(
encryptor.decryptString(user.getEncryptedCardNo);
}
}
@PrePersist
@PreUpdate
public void encrypt(Object pc) {
if (!(pc instanceof MyObj)) {
return;
}
MyObj obj = (MyObj ) pc;
if (obj.getCardNo() != null) {
user.setEncryptedCardNo(
encryptor.encryptString(user.getCardNo());
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用此方法,您可能必须采取一些预防措施以避免加密已加密的cardNo值.Transient无论是否cardNo已经加密,都可以使用附加属性来保存状态.
或者只是在entity属性的getter和setter中实现此功能.
public String getCardNo(){
return EncrypUtil.decrypt(this.cardNo);
}
public void setCardNo(String cardNo){
this.cardNo = EncrypUtil.encrypt(cardNo);
}
Run Code Online (Sandbox Code Playgroud)您还可以使用JPA供应商特定的拦截器.即HibernateInterceptors
public class CustomInterceptor extends EmptyInterceptor{
public boolean onSave(Object entity,Serializable id,
Object[] state,String[] propertyNames,Type[] types)
throws CallbackException {
if (entity instanceof MyObj){
// check if already encrypted or not.
//(A transient property could be useful)
entity.setCardNo(EncrypUtils.encrypt(entity.getCardNo()));
}
Run Code Online (Sandbox Code Playgroud)您还可以使用@Convert注释并指定转换器
@Convert(converter = CCConverter.class)
private String creditCardNumber;
Run Code Online (Sandbox Code Playgroud)
CCConverter 类应该是一个实现 AttributeConverter
希望这可以帮助.
| 归档时间: |
|
| 查看次数: |
9800 次 |
| 最近记录: |