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

时间:2015-12-14 03:46:46

标签: java hibernate jpa encryption interceptor

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

前: -

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

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

2 个答案:

答案 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)

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

  • 使用 JPA听众

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

<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

  • 的实现

希望这有帮助。