我正在为一个项目开发一些RESTFull Web服务。我使用Spring框架并使用gradle进行构建。 问题是,我想在写入和读取数据时加密和解密数据表。我已经有了一个用AES等加密和解密数据的算法(类)。我需要的是,如何注释这个方法来休眠实体类,我需要为这个类创建bean吗?
前: -
@Column(columnDefinition= "LONGBLOB", name = "card_no")
@ColumnTransformer(
read="decrypt(card_no)",
write="encrypt(?)")
private String cardNo;
像这样我想在这里添加我自己的加密/解密java方法。
答案 0 :(得分:8)
如果您有权访问JPA 2.1,我会主张使用@Convert
注释和AttributeConverter
实现。
AttributeConverter
定义实体属性在序列化到数据存储区时的状态与从数据存储区反序列化时的合约。
public class CreditCard {
@Convert(converter = CreditCardNumberConverter.class)
private String creditCardNumber;
}
您的转换器实现可能如下所示
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 */
}
}
如果您无法利用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);
}
}
执行上述操作可使对象中的实体状态保持一致,以确保数据库中存在的内容,而不会让Hibernate相信实体在加载数据库数据后立即更改。
答案 1 :(得分:6)
你可以用几种方式做到这一点。
以下是一个简单的例子。请相应更改。
<nav class="dt qf py tu eu app-navbar">
<div class="e">
<div class="pv">
<a class="l" href="../">
<span>Logo Here</span>
</a>
</div>
<div class="pw collapse" id="navbar-collapse">
<ul class="nav navbar-nav pk">
<li>
<a href="..//index.html">Home</a>
</li>
<li class="active">
<a href="../minimal/index.html">Index</a>
</li>
<li>
<a href="../bold/index.html">Bold</a>
</li>
<li>
<a href="../docs/index.html">Docs</a>
<li>
<a href="../docs/index.html">Mre Docs</a>
</li></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
使用这种方法,您可能需要采取一些预防措施,以避免加密已加密的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());
}
}
}
值。无论cardNo
是否已加密,都可以使用额外的Transient
属性来保存状态。
或者只是在实体属性的getter和setter中实现此功能。
cardNo
您还可以使用JPA供应商特定的拦截器。即 public String getCardNo(){
return EncrypUtil.decrypt(this.cardNo);
}
public void setCardNo(String cardNo){
this.cardNo = EncrypUtil.encrypt(cardNo);
}
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()));
}
注释并指定转换器
@Convert
@Convert(converter = CCConverter.class)
private String creditCardNumber;
类应该是CCConverter
希望这有帮助。