最开始学习shiro的时候需要自己保存User的salt, 最近系统升级,使用了Shiro1.3发现在1.2的时候Shiro提供了新的DefaultPasswordService来简化Password encode/match工作。很好奇为啥不在需要自己保存User的salt,查看了defaultpasswordservice的源代码,发现了其中的奥秘,具体看Shiro的代码(关注*部分),主要是重新构建Hash,然后从Hash中获取salt来做提交密码的hash,比较计算出来的hash和存储hash是否一致。
public boolean More ...passwordsMatch(Object submittedPlaintext, String saved) {
ByteSource plaintextBytes = createByteSource(submittedPlaintext);
if (saved == null || saved.length() == 0) {
return plaintextBytes == null || plaintextBytes.isEmpty();
} else {
if (plaintextBytes == null || plaintextBytes.isEmpty()) {
return false;
}
}
//First check to see if we can ***reconstitute the original hash*** - this allows us to
//perform password hash comparisons even for previously saved passwords that don‘t
//match the current HashService configuration values. This is a very nice feature
//for password comparisons because it ensures backwards compatibility even after
//configuration changes.
***HashFormat discoveredFormat = this.hashFormatFactory.getInstance(saved);***
<strong>if (discoveredFormat != null && discoveredFormat instanceof ParsableHashFormat) {
ParsableHashFormat parsableHashFormat = (ParsableHashFormat)discoveredFormat;
**Hash savedHash = parsableHashFormat.parse(saved);**
return ***passwordsMatch(submittedPlaintext, savedHash)***;
}</strong>
//If we‘re at this point in the method‘s execution, We couldn‘t reconstitute the original hash.
//So, we need to ***hash the submittedPlaintext using current HashService configuration and then
//compare the formatted output with the saved string. This will correctly compare passwords***,
//***but does not allow changing the HashService configuration without breaking previously saved
//passwords***:
//The saved text value can‘t be reconstituted into a Hash instance. We need to format the
//submittedPlaintext and then compare this formatted value with the saved value:
HashRequest request = createHashRequest(plaintextBytes);
Hash computed = this.hashService.computeHash(request);
String formatted = this.hashFormat.format(computed);
return saved.equals(formatted);
}
public boolean passwordsMatch(Object plaintext, Hash saved) {
ByteSource plaintextBytes = createByteSource(plaintext);
if (saved == null || saved.isEmpty()) {
return plaintextBytes == null || plaintextBytes.isEmpty();
} else {
if (plaintextBytes == null || plaintextBytes.isEmpty()) {
return false;
}
}
HashRequest request = ***buildHashRequest(plaintextBytes, saved);***
Hash computed = this.hashService.computeHash(request);
return saved.equals(computed);
}
protected HashRequest buildHashRequest(ByteSource plaintext, Hash saved) {
//keep everything from the saved hash except for the source:
return new HashRequest.Builder().setSource(plaintext)
//now use the existing saved data:
.setAlgorithmName(saved.getAlgorithmName())
.***setSalt(saved.getSalt())***
.setIterations(saved.getIterations())
.build();
}
要使用defaultpasswordService非常简单就是简单的spring bean,当然你可以通过注入改变迭代次数和加密算法。
<bean name="passwordService" class="org.apache.shiro.authc.credential.DefaultPasswordService" />
时间: 2024-10-15 03:11:12