首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在spring项目中使用自定义语法(Hibernate)对数据进行加密/解密

如何在spring项目中使用自定义语法(Hibernate)对数据进行加密/解密
EN

Stack Overflow用户
提问于 2015-12-14 11:46:46
回答 2查看 14.5K关注 0票数 9

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

例如:-

代码语言:javascript
复制
@Column(columnDefinition= "LONGBLOB", name = "card_no")
        @ColumnTransformer(
                read="decrypt(card_no)",
                write="encrypt(?)")
        private String cardNo;

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

EN

回答 2

Stack Overflow用户

发布于 2015-12-14 13:43:16

如果您能够使用JPA2.1,我建议在AttributeConverter实现中使用@Convert注释。

AttributeConverter定义了实体属性在序列化到数据存储时和从数据存储反序列化时的状态之间的协定。

代码语言:javascript
复制
public class CreditCard {
  @Convert(converter = CreditCardNumberConverter.class)
  private String creditCardNumber;
}

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

代码语言:javascript
复制
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 */
  }
}

如果您不能利用JPA2.1,那么可以使用EntityListener或使用@PrePersist@PreUpdate@PostLoad来执行类似的逻辑来加密和解密数据库值。

如果您决定使用EntityListener或任何Pre/Post回调方法注释,请确保将解密结果存储在一个瞬态字段中,并将该字段用作您的业务层,如下所示:

代码语言:javascript
复制
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认为实体在加载数据库数据后立即发生了变化。

票数 15
EN

Stack Overflow用户

发布于 2015-12-14 12:53:18

您可以通过几种方式来完成此操作。

使用JPA Listeners的

下面是一个简单的例子。请做相应的修改。

代码语言:javascript
复制
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值。无论cardNo是否已经加密,都可以使用一个附加的Transient属性来保存状态。

实体或简单地在

  • 属性的getter和setter中实现此功能。

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

  • 您也可以使用特定于JPA供应商的拦截器。即HibernateInterceptors

公共类CustomInterceptor扩展EmptyInterceptor{公共布尔onSave(对象实体,可序列化id,Object[]状态,String[] propertyNames,Type[]类型)抛出CallbackException { if ( entity instanceof MyObj){ //检查是否已加密。//(瞬态属性可能很有用) entity.setCardNo(EncrypUtils.encrypt(entity.getCardNo()));}

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

@Convert(converter = CCConverter.class)私有字符串creditCardNumber;

应该是AttributeConverter的实现的CCConverter

希望这能有所帮助。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34259457

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档