Java Hibernate—将列存储为加密列,并仅在运行时解密
当从hibernate支持的webapp传递时,我有一个需要加密的数据库列。webapp在Tomcat6、Hibernate4和Mysql上作为备份存储 但问题是,加密/解密此字段的密码仅在程序运行时可用。最初,我希望使用AES_加密/解密方法,这里概述得相当清楚: 在这里: (虽然这确实是指hibernate的3.6版,但我相信它在4.0中应该是相同的) 但是,由于它使用以下符号:Java Hibernate—将列存储为加密列,并仅在运行时解密,java,mysql,hibernate,security,encryption,Java,Mysql,Hibernate,Security,Encryption,当从hibernate支持的webapp传递时,我有一个需要加密的数据库列。webapp在Tomcat6、Hibernate4和Mysql上作为备份存储 但问题是,加密/解密此字段的密码仅在程序运行时可用。最初,我希望使用AES_加密/解密方法,这里概述得相当清楚: 在这里: (虽然这确实是指hibernate的3.6版,但我相信它在4.0中应该是相同的) 但是,由于它使用以下符号: @Column(columnDefinition= "LONGBLOB", name="encryptedB
@Column(columnDefinition= "LONGBLOB", name="encryptedBody")
@ColumnTransformer(
read="AES_DECRYPT(encryptedBody, 'password')",
write="AES_ENCRYPT(?, 'password')")
public byte[] getEncryptedBody() {
return encryptedBody;
}
public void setEncryptedBody(byte[] encryptedBody) {
this.encryptedBody = encryptedBody;
}
这要求在注释本身中指定密码,并且不能是变量
有没有一种方法可以通过hibernate以这种方式使用数据库方法,但密码是一个变量?有更好的方法吗?目前没有一种方法可以参数化读/写片段。它们更像是通用解决方案。我们已经讨论过在Hibernate中添加对@Encrypted的支持,这将大致按照您的建议执行@加密将提供更大的灵活性,如vm加密与db加密、参数化等
JPA2.1还有一个可以使用的特性,叫做属性转换器。但是,它们只能在vm crypto中应用。您可以使用Hibernate@Type属性,根据您的要求,您可以自定义注释并在脚本上应用。比如:
public class PhoneNumberType implements UserType {
@Override
public int[] sqlTypes() {
return new int[]{Types.INTEGER, Types.INTEGER, Types.INTEGER};
}
@Override
public Class returnedClass() {
return PhoneNumber.class;
}
// other methods
}
首先,null SafeGet方法:
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SharedSessionContractImplementor session, Object owner) throws HibernateException,
SQLException {
int countryCode = rs.getInt(names[0]);
if (rs.wasNull())
return null;
int cityCode = rs.getInt(names[1]);
int number = rs.getInt(names[2]);
PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);
return employeeNumber;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value,
int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if (Objects.isNull(value)) {
st.setNull(index, Types.INTEGER);
} else {
PhoneNumber employeeNumber = (PhoneNumber) value;
st.setInt(index,employeeNumber.getCountryCode());
st.setInt(index+1,employeeNumber.getCityCode());
st.setInt(index+2,employeeNumber.getNumber());
}
}
接下来,null SafeSet方法:
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SharedSessionContractImplementor session, Object owner) throws HibernateException,
SQLException {
int countryCode = rs.getInt(names[0]);
if (rs.wasNull())
return null;
int cityCode = rs.getInt(names[1]);
int number = rs.getInt(names[2]);
PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);
return employeeNumber;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value,
int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if (Objects.isNull(value)) {
st.setNull(index, Types.INTEGER);
} else {
PhoneNumber employeeNumber = (PhoneNumber) value;
st.setInt(index,employeeNumber.getCountryCode());
st.setInt(index+1,employeeNumber.getCityCode());
st.setInt(index+2,employeeNumber.getNumber());
}
}
最后,我们可以在OfficeEmployee实体类中声明自定义PhoneNumberType:
@Entity
@Table(name = "OfficeEmployee")
public class OfficeEmployee {
@Columns(columns = { @Column(name = "country_code"),
@Column(name = "city_code"), @Column(name = "number") })
@Type(type = "com.baeldung.hibernate.customtypes.PhoneNumberType")
private PhoneNumber employeeNumber;
// other fields and methods
}
这可能会解决您的问题,这将适用于所有数据库。如果您想了解更多信息,请参考::同样,您必须进行UTF-8编码/解码和ISO-8859-1解码/编码我建议使用