前言
我们知道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);
}
}