我正在使用Play 1.2.1。我想散列我的用户密码。我原以为Crypto.passwordHash
会很好,但事实并非如此。passwordHash文档说它返回MD5密码散列。我在fixture中创建了一些用户帐户,在那里我放置了md5密码哈希:
...
User(admin):
login: admin
password: f1682b54de57d202ba947a0af26399fd
fullName: Administrator
...
问题是,当我尝试登录时,会出现这样的情况:
user.password.equals(Crypto.passwordHash(password))
但它不起作用。所以我在我的autentify
方法中放了一条日志语句:
Logger.info("nUser hashed password is %s " +
"nPassed password is %s " +
"nHashed passed password is %s",
user.password, password, Crypto.passwordHash(password));
密码散列确实不同,但是嘿!passwordHash
方法的输出甚至不是MD5散列:
15:02:16,164 INFO ~
User hashed password is f1682b54de57d202ba947a0af26399fd
Passed password is <you don't have to know this :P>
Hashed passed password is 8WgrVN5X0gK6lHoK8mOZ/Q==
怎么样?如何修复?或者我必须实现自己的解决方案?
Crypto.passwordHash返回base64编码的密码哈希,而您正在与十六进制编码进行比较。
MD5输出一个16个字节的序列,每个字节(可能)具有0到255(包括0和255)之间的任何值。当您想打印值时,需要将字节转换为"可打印字符"序列。有几种可能的约定,两种主要的是十六进制和Base64。
在十六进制表示法中,每个字节值都表示为两个"十六进制数字":这样的数字要么是十进制数字(从"0"到"9"),要么是字母(从"a"到"f",大小写无关)。因此,16个字节变为32个字符。
在Base64编码中,每组三个连续字节被编码为四个字符,包含64个可能的字符(数字、小写字母、大写字母、"+"one_answers"/")。可以添加一个或两个最后的"="符号,以便编码字符串由4的倍数的多个字符组成。
这里,'8WgrVN5X0gK6lHoK8mOZ/Q=='是一个16字节序列的Base64编码,第一个字节的值为241,第二个字节为104,然后为43,依此类推。在十六进制记数法中,第一字节用'f1'表示,第二字节用'68',第三字节用'2b'表示。。。16个字节的完整序列的十六进制表示法是"f1682b54de57d202ba947a0af2639fd",这是您所期望的值。
play.libs.Codec类包含用于解码和编码Base64和十六进制符号的方法。它还包含执行MD5散列的Codec.hexMD5()
,并以十六进制表示法而不是Base64返回值。
正如Nickolay所说,您正在比较十六进制字符串与Base-64字符串。此外,我建议使用BCrypt,而不是Play的加密工具。