当前位置:  开发笔记 > 编程语言 > 正文

如何在spring项目中使用自定义anotation(hibernate)加密/解密数据

如何解决《如何在spring项目中使用自定义anotation(hibernate)加密/解密数据》经验,为你挑选了2个好方法。

我正在为一个项目开发一些RESTFull Web服务.我使用Spring框架并使用gradle进行构建.问题是,我想在写入和读取数据时加密和解密数据表.我已经有了一个用AES等加密和解密数据的算法(类).我需要的是,如何注释这个方法来休眠实体类,我需要为这个类创建bean吗?

例如: -

@Column(columnDefinition= "LONGBLOB", name = "card_no")
        @ColumnTransformer(
                read="decrypt(card_no)",
                write="encrypt(?)")
        private String cardNo;

像这样我想在这里添加我自己的加密/解密java方法.



1> Naros..:

如果您可以访问JPA 2.1,我会主张使用@Convert带有AttributeConverter实现的注释.

一个AttributeConverter限定了一个实体属性的状态之间的合同,当它是序列化到数据存储,并且当它被从数据存储反序列化.

public class CreditCard {
  @Convert(converter = CreditCardNumberConverter.class)
  private String creditCardNumber;
}

您的转换器实现可能如下所示

public class CreditCardNumberConverter implements AttributeConverter {
  @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相信实体在加载数据库数据后立即更改.



2> tharindu_DG..:

你可以用几种方式做到这一点.

使用JPA Listeners

以下是一个简单的例子.请相应更改.

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无论是否cardNo已经加密,都可以使用附加属性来保存状态.

或者只是在entity属性的getter和setter中实现此功能.

 public String getCardNo(){
     return EncrypUtil.decrypt(this.cardNo);
 }

 public void setCardNo(String cardNo){
     this.cardNo = EncrypUtil.encrypt(cardNo);
 }

您还可以使用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()));
         }

您还可以使用@Convert注释并指定转换器

    @Convert(converter = CCConverter.class)
    private String creditCardNumber;

CCConverter 类应该是一个实现 AttributeConverter

希望这可以帮助.

推荐阅读
echo7111436
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有