【问题标题】:java.lang.ClassCastException: [B cannot be cast to java.lang.Stringjava.lang.ClassCastException: [B 不能转换为 java.lang.String
【发布时间】:2012-12-10 22:47:58
【问题描述】:

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

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

我只想检索已解密的密码。所以,我在 OPen JPA 2.0 中使用 AES_DECRYPT 使用 NAtiveQueryis。

我写的查询是:

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 有库可以为您做这件事,为什么还要使用数据库来做这件事?
  • 不加密密码。密码应该被安全地散列;永远不可能找回密码。
  • 当数据库提供开箱即用的Java库时,为什么还要使用Java库,这样密码甚至不必离开数据库?

标签: java jpa jpa-2.0 openjpa blueprint-osgi


【解决方案1】:

类似问题:What kind of Java type is "[B"?

MySQL 的AES_DECRYPT 确实返回String,而是返回一个字节数组,用“[B”表示。将结果转换为 byte[] 并从中构建您的字符串。

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

您可以使用 MySQL 轻松做到这一点,因为它已经提供了必要的functions:MD5(被认为是不安全的)、SHA1(几乎是标准的)和 SHA2(甚至比 SHA1 更安全)。

所以你的方案基本上可能是这样的:

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是要验证的密码。

有关更多信息,请在 Internet 上搜索“密码哈希”,例如参见 herehere

如果需要,这些散列操作也可以在您的数据库客户端代码中完成。

【讨论】:

  • 使用数据库功能加密并保存密码不是一个好的设计吗??
猜你喜欢
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-05
  • 2012-02-09
  • 2021-04-30
  • 2018-11-11
相关资源
最近更新 更多