尝试应用AttributeConverter时出错;最后一个单元没有足够的有效位



我正在尝试使用属性转换器来转换类中的两个字段。我非常忠实地遵循了这些教程,但仍然会出现这个奇怪的错误。https://sultanov.dev/blog/database-column-level-encryption-with-spring-data-jpa/https://beingcrazydev.com/spring-data-jpa-database-column-encryption/https://thorben-janssen.com/how-to-use-jpa-type-converter-to/

以下是我一直收到的错误消息的缩短版本:

Error attempting to apply AttributeConverter; nested exception is javax.persistence.PersistenceException: Error attempting to apply AttributeConverter
org.springframework.orm.jpa.JpaSystemException: Error attempting to apply AttributeConverter; nested exception is javax.persistence.PersistenceException: Error attempting to apply AttributeConverter
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:408)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy88.save(Unknown Source)
at swe.bookstore.controller.RegisterController.createAccount(RegisterController.java:58)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
Caused by: javax.persistence.PersistenceException: Error attempting to apply AttributeConverter
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.doConversion(AttributeConverterSqlTypeDescriptorAdapter.java:148)
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.extract(AttributeConverterSqlTypeDescriptorAdapter.java:121)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243)
at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:329)
Caused by: java.lang.IllegalArgumentException: Last unit does not have enough valid bits
at java.base/java.util.Base64$Decoder.decode0(Base64.java:766)
at java.base/java.util.Base64$Decoder.decode(Base64.java:538)
at java.base/java.util.Base64$Decoder.decode(Base64.java:561)
at swe.bookstore.entity.AttributeEncryptor.convertToEntityAttribute(AttributeEncryptor.java:44)
at swe.bookstore.entity.AttributeEncryptor.convertToEntityAttribute(AttributeEncryptor.java:14)
at org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl.toDomainValue(JpaAttributeConverterImpl.java:45)
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.doConversion(AttributeConverterSqlTypeDescriptorAdapter.java:140)
... 134 more

这是我的代码:

@Component
public class AttributeEncryptor implements AttributeConverter<String, String> {
private static final String AES = "AES";
private static final byte[] encryptionKey = "123-a-secret-key".getBytes(); // do not change this!!
private final Key key;
private final Cipher encryptCipher;
private final Cipher decryptCipher;
public AttributeEncryptor() throws Exception {
key = new SecretKeySpec(encryptionKey, AES);
encryptCipher = Cipher.getInstance(AES);
decryptCipher = Cipher.getInstance(AES);
}
@Override
public String convertToDatabaseColumn(String attribute) {
try {
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
return Base64.getEncoder().encodeToString(encryptCipher.doFinal(attribute.getBytes()));
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public String convertToEntityAttribute(String dbData) {
try {
decryptCipher.init(Cipher.DECRYPT_MODE, key);
return new String(decryptCipher.doFinal(Base64.getDecoder().decode(dbData)));
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalArgumentException(e);
}
}
}

以及我如何将其应用于持久性领域:

@Column(name = "cardNumber", nullable = false)
@Convert(converter = AttributeEncryptor.class)
private String cardNumber;
@Column(name = "`password`", nullable = false, length = 20)
@Convert(converter = AttributeEncryptor.class)
private String password;

我不明白哪里出了问题,因为我按照教程中的步骤进行了操作。

无论你遵循了什么教程,它都是错误的。Cipher不是线程安全的,所以应该使用本地线程。另请参阅密码线程安全吗?

最新更新