Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Spring数据JPA和JPA EntityListener进行字段级加密_Java_Spring_Hibernate_Jpa_Encryption - Fatal编程技术网

Java 使用Spring数据JPA和JPA EntityListener进行字段级加密

Java 使用Spring数据JPA和JPA EntityListener进行字段级加密,java,spring,hibernate,jpa,encryption,Java,Spring,Hibernate,Jpa,Encryption,我试图在插入/更新之前加密域实体上的一些字段,并在选择显示在UI中时解密它们 我将SpringDataJPA存储库与Hibernate和EntityListener一起使用,它在@PostLoadLifecycle事件期间解密,在@PrePersist和@PreUpdate期间加密。我遇到的问题是,一旦记录从DB加载到PersistenceContext中,侦听器就会解密数据,这使EntityManager认为实体已被更改,从而触发更新,从而再次触发@PreUpdate加密。如何处理这个问题有什

我试图在插入/更新之前加密域实体上的一些字段,并在选择显示在UI中时解密它们

我将SpringDataJPA存储库与Hibernate和EntityListener一起使用,它在@PostLoadLifecycle事件期间解密,在@PrePersist和@PreUpdate期间加密。我遇到的问题是,一旦记录从DB加载到PersistenceContext中,侦听器就会解密数据,这使EntityManager认为实体已被更改,从而触发更新,从而再次触发@PreUpdate加密。如何处理这个问题有什么建议吗

  • 弹簧4.0.4.1释放
  • Spring数据JPA 1.5.2.1版本
  • 冬眠4.2.14.1决赛
有没有一种简单的方法可以从JPA存储库返回分离的实体

实体类

@Entity
@Table(name="cases")
@EntityListeners(EncryptionListener.class)
public class MyCase implements Serializable, EncryptionEntity {

private static final Logger logger = LoggerFactory.getLogger(MyCase.class);

private static final long serialVersionUID = 1L;

private String caseNumber;
private byte[] secretProperty;
private byte[] iv;

@Id
@Column(name="case_number")
public String getCaseNumber() {
    return caseNumber;
}
public void setCaseNumber(String caseNumber) {
    this.caseNumber = caseNumber;
}

@Column(name="secret_property")
public byte[] getSecretProperty() {
    return secretProperty;
}
public void setSecretProperty(byte[] secretProperty) {
    this.secretProperty = secretProperty;
}

@Column
public byte[] getIv() {
    return iv;
}
public void setIv(byte[] iv) {
    this.iv = iv;
}

@Override
@Transient
public byte[] getInitializationVector() {
    return this.iv;
}

@Override
public void setInitializationVector(byte[] iv) {
    this.setIv(iv);
}

}
@Component
public class EncryptionListener {

    private static final Logger logger = LoggerFactory.getLogger(EncryptionListener.class);

    private static EncryptionUtils encryptionUtils;
    private static SecureRandom secureRandom;

    private static Map<Class<? extends EncryptionEntity>, 
        List<EncryptionEntityProperty>> propertiesToEncrypt;

    @Autowired
    public void setCrypto(EncryptionUtils encryptionUtils){
        EncryptionListener.encryptionUtils = encryptionUtils;
    }

    @Autowired
    public void setSecureRandom(SecureRandom secureRandom){
        EncryptionListener.secureRandom = secureRandom;
    }

    public EncryptionListener(){

        if (propertiesToEncrypt == null){

            propertiesToEncrypt = new HashMap<Class<? extends EncryptionEntity>, List<EncryptionEntityProperty>>();

            //MY CASE
            List<EncryptionEntityProperty> propertyList = new ArrayList<EncryptionEntityProperty>();
            propertyList.add(new EncryptionEntityProperty(MyCase.class, "secretProperty", byte[].class));
            propertiesToEncrypt.put(MyCase.class, propertyList);

        }

    }

    @PrePersist
    public void prePersistEncryption(EncryptionEntity entity){
        logger.debug("PRE-PERSIST");
        encryptFields(entity);
    }

    @PreUpdate
    public void preUpdateEncryption(EncryptionEntity entity){
        logger.debug("PRE-UPDATE");
        encryptFields(entity); 
    }

    public void encryptFields(EncryptionEntity entity){
        byte[] iv = new byte[16];
        secureRandom.nextBytes(iv);
        encryptionUtils.setIv(iv);
        entity.setInitializationVector(iv);

        logger.debug("Encrypting " + entity);

        Class<? extends EncryptionEntity> entityClass = entity.getClass();

        List<EncryptionEntityProperty> properties = propertiesToEncrypt.get(entityClass);

        for (EncryptionEntityProperty property : properties){

            logger.debug("Encrypting '{}' field of {}", property.getName(), entityClass.getSimpleName());
            if (property.isEncryptedWithIv() == false){
                logger.debug("Encrypting '{}' without IV.", property.getName());
            }

            try {
                byte[] bytesToEncrypt = (byte[]) property.getGetter().invoke(entity, (Object[]) null);

                if (bytesToEncrypt == null || bytesToEncrypt.length == 0){
                    continue;
                }

                byte[] encrypted = encryptionUtils.encrypt(bytesToEncrypt, property.isEncryptedWithIv());

                property.getSetter().invoke(entity, new Object[]{encrypted});


            } catch (Exception e){
                logger.error("Error while encrypting '{}' property of {}: " + e.getMessage(), property.getName(), entityClass.toString());
                e.printStackTrace();
            }

        }

    }

    @PostLoad
    public void decryptFields(EncryptionEntity entity){

        logger.debug("POST-LOAD");

        logger.debug("Decrypting " + entity);

        Class<? extends EncryptionEntity> entityClass = entity.getClass();
        byte[] iv = entity.getInitializationVector();

        List<EncryptionEntityProperty> properties = propertiesToEncrypt.get(entityClass);

        for (EncryptionEntityProperty property : properties){

            try {
                byte[] value = (byte[]) property.getGetter().invoke(entity, (Object[]) null);

                if (value == null || value.length == 0){
                    logger.debug("Ignoring blank field {} of {}", property.getName(), entityClass.getSimpleName());
                    continue;
                } 

                logger.debug("Decrypting '{}' field of {}", property.getName(), entityClass.getSimpleName());
                if (property.isEncryptedWithIv() == false){
                    logger.debug("Decrypting '{}' without IV.", property.getName());
                }

                byte[] decrypted = encryptionUtils.decrypt(value, iv, property.isEncryptedWithIv());

                property.getSetter().invoke(entity, new Object[]{decrypted});

            } catch (Exception e){
                logger.error("Error while decrypting '{}' property of {}", property.getName(), entityClass.toString());
                e.printStackTrace();
            }
        }

    }



}
加密实体接口

public interface EncryptionEntity {

    public byte[] getInitializationVector();
    public void setInitializationVector(byte[] iv);
}
public interface MyCaseService {

    public MyCase findOne(String caseNumber);

    public MyCase save(MyCase case);

}
Spring数据JPA存储库

public interface MyCaseRepository extends JpaRepository<MyCase, String> {

}
MyCaseService实施

public class MyCaseServiceImpl implements MyCaseService {

    private static final Logger logger = LoggerFactory.getLogger(MyCaseServiceImpl.class);

    @Autowired
    private MyCaseRepository repos;


    @Override
    public MyCase findOne(String caseNumber) {
        return repos.findOne(caseNumber);
    }

    @Transactional(readOnly=false)
    public MyCase save(MyCase case) {

        return repos.save(case);
    }

}
加密JPA侦听器类

@Entity
@Table(name="cases")
@EntityListeners(EncryptionListener.class)
public class MyCase implements Serializable, EncryptionEntity {

private static final Logger logger = LoggerFactory.getLogger(MyCase.class);

private static final long serialVersionUID = 1L;

private String caseNumber;
private byte[] secretProperty;
private byte[] iv;

@Id
@Column(name="case_number")
public String getCaseNumber() {
    return caseNumber;
}
public void setCaseNumber(String caseNumber) {
    this.caseNumber = caseNumber;
}

@Column(name="secret_property")
public byte[] getSecretProperty() {
    return secretProperty;
}
public void setSecretProperty(byte[] secretProperty) {
    this.secretProperty = secretProperty;
}

@Column
public byte[] getIv() {
    return iv;
}
public void setIv(byte[] iv) {
    this.iv = iv;
}

@Override
@Transient
public byte[] getInitializationVector() {
    return this.iv;
}

@Override
public void setInitializationVector(byte[] iv) {
    this.setIv(iv);
}

}
@Component
public class EncryptionListener {

    private static final Logger logger = LoggerFactory.getLogger(EncryptionListener.class);

    private static EncryptionUtils encryptionUtils;
    private static SecureRandom secureRandom;

    private static Map<Class<? extends EncryptionEntity>, 
        List<EncryptionEntityProperty>> propertiesToEncrypt;

    @Autowired
    public void setCrypto(EncryptionUtils encryptionUtils){
        EncryptionListener.encryptionUtils = encryptionUtils;
    }

    @Autowired
    public void setSecureRandom(SecureRandom secureRandom){
        EncryptionListener.secureRandom = secureRandom;
    }

    public EncryptionListener(){

        if (propertiesToEncrypt == null){

            propertiesToEncrypt = new HashMap<Class<? extends EncryptionEntity>, List<EncryptionEntityProperty>>();

            //MY CASE
            List<EncryptionEntityProperty> propertyList = new ArrayList<EncryptionEntityProperty>();
            propertyList.add(new EncryptionEntityProperty(MyCase.class, "secretProperty", byte[].class));
            propertiesToEncrypt.put(MyCase.class, propertyList);

        }

    }

    @PrePersist
    public void prePersistEncryption(EncryptionEntity entity){
        logger.debug("PRE-PERSIST");
        encryptFields(entity);
    }

    @PreUpdate
    public void preUpdateEncryption(EncryptionEntity entity){
        logger.debug("PRE-UPDATE");
        encryptFields(entity); 
    }

    public void encryptFields(EncryptionEntity entity){
        byte[] iv = new byte[16];
        secureRandom.nextBytes(iv);
        encryptionUtils.setIv(iv);
        entity.setInitializationVector(iv);

        logger.debug("Encrypting " + entity);

        Class<? extends EncryptionEntity> entityClass = entity.getClass();

        List<EncryptionEntityProperty> properties = propertiesToEncrypt.get(entityClass);

        for (EncryptionEntityProperty property : properties){

            logger.debug("Encrypting '{}' field of {}", property.getName(), entityClass.getSimpleName());
            if (property.isEncryptedWithIv() == false){
                logger.debug("Encrypting '{}' without IV.", property.getName());
            }

            try {
                byte[] bytesToEncrypt = (byte[]) property.getGetter().invoke(entity, (Object[]) null);

                if (bytesToEncrypt == null || bytesToEncrypt.length == 0){
                    continue;
                }

                byte[] encrypted = encryptionUtils.encrypt(bytesToEncrypt, property.isEncryptedWithIv());

                property.getSetter().invoke(entity, new Object[]{encrypted});


            } catch (Exception e){
                logger.error("Error while encrypting '{}' property of {}: " + e.getMessage(), property.getName(), entityClass.toString());
                e.printStackTrace();
            }

        }

    }

    @PostLoad
    public void decryptFields(EncryptionEntity entity){

        logger.debug("POST-LOAD");

        logger.debug("Decrypting " + entity);

        Class<? extends EncryptionEntity> entityClass = entity.getClass();
        byte[] iv = entity.getInitializationVector();

        List<EncryptionEntityProperty> properties = propertiesToEncrypt.get(entityClass);

        for (EncryptionEntityProperty property : properties){

            try {
                byte[] value = (byte[]) property.getGetter().invoke(entity, (Object[]) null);

                if (value == null || value.length == 0){
                    logger.debug("Ignoring blank field {} of {}", property.getName(), entityClass.getSimpleName());
                    continue;
                } 

                logger.debug("Decrypting '{}' field of {}", property.getName(), entityClass.getSimpleName());
                if (property.isEncryptedWithIv() == false){
                    logger.debug("Decrypting '{}' without IV.", property.getName());
                }

                byte[] decrypted = encryptionUtils.decrypt(value, iv, property.isEncryptedWithIv());

                property.getSetter().invoke(entity, new Object[]{decrypted});

            } catch (Exception e){
                logger.error("Error while decrypting '{}' property of {}", property.getName(), entityClass.toString());
                e.printStackTrace();
            }
        }

    }



}
@组件
公共类EncryptionListener{
私有静态最终记录器Logger=LoggerFactory.getLogger(EncryptionListener.class);
私有静态加密utils EncryptionUtils;
私有静态SecureRandom SecureRandom;

private static Map我知道所问的问题已经很老了。但我也面临着同样的问题,要解决这个问题,您可以使用PreLoad eventlistener。在
解密字段中,使用
@PostLoad
而不是
@PostLoad

调用
@PostLoad
时调用
findOne(字符串caseNumber)
method?@wypiperpz,是的,@PostLoad方法由findOne方法触发。secretProperty解密后,@PostUpdate立即触发。在持久性上下文之外执行
MyCaseServiceImpl.findOne
方法如何?然后实体应作为分离的实体返回。Spring创建一个prox使用EntityManager的MyCaseRepository的y。不确定如何避免持久性上下文。也许如果我没有使用
@Transactional
注释findOne方法,我已经转向了另一种方法,使用EncryptionListener作为注入组件进行加密/解密。但它肯定没有transpar那么优雅我希望使用ent加密/解密。我猜
@Transactional(传播=传播。不受支持)
将强制分离。