java.lang.ClassCastException: [B 无法转换为 java.lang.String

8

我已经编写了一个实体类,其中包含字段LoginId和Password。

我正在使用AES_ENCRYPT对密码进行加密,并将其存储在数据库中。

我想要检索解密后的密码。因此,我正在使用Open JPA 2.0中的NativeQuery和AES_DECRYPT。

我编写的查询语句是:

Query q = em.createNativeQuery("select AES_DECRYPT(l.password,?2) from loginDetails l where l.loginID = ?1");
q.setParameter(1, loginId);
q.setParameter(2, getKey());
String s = q.getSingleResult();  

但是我遇到了以下异常:

java.lang.ClassCastException: [B cannot be cast to java.lang.String
at com.rcs.chef.validation.UserValidation.decryptedPasswordForID(UserValidation.java:99)
at com.rcs.chef.validation.UserValidation.validateUser(UserValidation.java:81)
at com.rcs.chef.validation.UserValidation.activate(UserValidation.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.aries.blueprint.utils.ReflectionUtils.invoke(ReflectionUtils.java:226)
at org.apache.aries.blueprint.container.BeanRecipe.invoke(BeanRecipe.java:824)
at org.apache.aries.blueprint.container.BeanRecipe.runBeanProcInit(BeanRecipe.java:636)
at org.apache.aries.blueprint.container.BeanRecipe.internalCreate(BeanRecipe.java:724)
at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:64)
at org.apache.aries.blueprint.container.BlueprintRepository.createInstances(BlueprintRepository.java:219)
at org.apache.aries.blueprint.container.BlueprintRepository.createAll(BlueprintRepository.java:147)
at org.apache.aries.blueprint.container.BlueprintContainerImpl.instantiateEagerComponents(BlueprintContainerImpl.java:640)
at org.apache.aries.blueprint.container.BlueprintContainerImpl.doRun(BlueprintContainerImpl.java:331)
at org.apache.aries.blueprint.container.BlueprintContainerImpl.run(BlueprintContainerImpl.java:227)

我甚至尝试了这个:

Query q = em.createNativeQuery("select AES_DECRYPT(l.password,?2) from loginDetails l where l.loginID = ?1");
q.setParameter(1, loginId);
q.setParameter(2, getKey());
List<Object> s = q.getResultList();  

String s1 = null;
for(Object o : s){
    s1= (String) o;
}

即使在这里,我也遇到了相同的异常:
java.lang.ClassCastException: [B cannot be cast to java.lang.Object

你能告诉我查询和处理请求的错误在哪里吗?


Java已经有库可以做这件事,为什么还要使用数据库呢? - fge
1
不要加密密码。密码应该被安全地“哈希化”,永远不应该能够检索出密码。 - SLaks
为什么要使用Java库,当数据库已经提供了这个功能,使得密码甚至不必离开数据库? - JimmyB
1个回答

10

类似的问题:什么样的Java类型是“[B”?

MySQL的AES_DECRYPT不返回一个String,而是一个由“[B”表示的字节数组。将结果转换为byte[]并通过此构建字符串。

看起来你甚至不需要解密密码;你只想要validateUser,对吗? - 在这种情况下,就像其他人指出的那样,应该使用安全哈希。

你可以很容易地在MySQL中实现这一点,因为它已经提供了必要的函数:MD5(被认为是不安全的),SHA1(几乎是标准),以及比SHA1更安全的SHA2。

所以你的计划基本上可能是这样的:

insert into loginDetails (..., passwordHashSalt, passwordHash) values ( ..., ?1, SHA1(CONCAT( ?1, ?2 )) ),其中?1设置为唯一的“salt”,例如用户名本身,?2是实际密码。请注意,盐必须也存储在数据库中,并且对于每个用户/密码都“必须”唯一;因此,用户名是这个的自然选择。

然后,要验证给定的密码,可以执行以下操作:

select 'OK' from loginDetails where ... and passwordHash = SHA1(CONCAT( passwordHashSalt, ?1 )),其中?1是要验证的密码。

更多信息请在互联网上搜索'密码哈希',例如,请查看这里这里。 这些哈希操作也可以在您的数据库客户端代码中完成,如果需要的话。

将密码加密并使用数据库函数保存它们不是一个好的设计吗? - user1909657

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接