前言
我們知道Shiro框架有提供憑證匹配器類HashedCredentialsMatcher來實現密碼校驗的,在該類中可以自定義加密方式、加密次數、編碼規則等
//權限管理
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm(hashedCredentialsMatcher()));
return securityManager;
}
//憑證匹配器
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//採用SHA-512方式加密
hashedCredentialsMatcher.setHashAlgorithmName("SHA-512");
//設置加密次數
hashedCredentialsMatcher.setHashIterations(1024);
//true加密用的hex編碼,false用的base64編碼
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(false);
return hashedCredentialsMatcher;
}
如上圖,假如我們採用SHA-512的加密方式,加密次數爲1024次,採用base64的編碼方式,來看一下是如何實現密碼校驗的
打開HashedCredentialsMatcher類的源碼
可以看到,他是通過doCredentialsMatch方法來進行判斷的,其中參數AuthenticationToken包含用戶輸入的密碼信息,AuthenticationInfo包含用戶的身份認證信息(如庫中存入的密碼、鹽值等信息)
先進入hashProvidedCredentials方法看一下他的實現
這裏先進行判斷,取到用戶設置的鹽值salt,然後調用了hashProvidedCredentials方法
發現最後是通過new SimpleHash方法,分別傳入加密方式、用戶輸入的密碼、庫中存入的鹽值、加密次數,來生成加密後的密碼
再進入getCredentials方法看一下他的實現
這裏先判斷在憑證匹配器中設置的編碼方式,由於前面setStoredCredentialsHexEncoded方法設置的false,所以這裏採用Base64的方式來進行解碼,最終返回庫中密碼進行Base64解碼後的值,所以我們庫中存入的密碼是加密後再進行Base64編碼後的值
模擬Shiro框架的密碼校驗
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.stereotype.Controller;
@Controller
public class EncodePassTest {
public static void main(String[] args) throws Exception {
String password = "123456";//原密碼
String hashAlgorithmName = "SHA-512";//加密方式
int hashIterations = 1024; //加密次數
//生成隨機鹽值
String salt = new SecureRandomNumberGenerator().nextBytes().toBase64();
//密碼和鹽值加密並轉爲Base64
String dbPassord = new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toBase64();
System.out.println("加密後需入庫的密碼:"+dbPassord);
/*校驗密碼*/
//庫中的密碼Base64解密後,對應shiro的getCredentials方法
SimpleHash dbPassordDecode = new SimpleHash(hashAlgorithmName);
dbPassordDecode.setBytes(Base64.decode(dbPassord));
System.out.println("庫中的密碼Base64解密後:"+dbPassordDecode);
//用戶輸入的密碼加密後,對應shiro的hashProvidedCredentials方法
SimpleHash tokenHashedCredentials = new SimpleHash(hashAlgorithmName, password, salt, hashIterations);
System.out.println("用戶輸入的密碼加密後:"+tokenHashedCredentials);
}
}