Shiro采用HashedCredentialsMatcher进行密码匹配。

启用Shiro的密码匹配

采用Shiro的密码认证首先需要在Realm中配置

1
2
3
4
5
6
7
8
9
10
11
<bean id="userRealm" class="com.hello.UserRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 散列算法名 -->
<property name="hashAlgorithmName" value="SHA-512"></property>
<property name="hashIterations" value="1024"></property>
<!-- 密码采用Base64解码 -->
<property name="storedCredentialsHexEncoded" value="false"></property>
</bean>

原理分析

只要配置了HashedCredentialsMatcher就会进入到该类的doCredentialsMatch()方法中

1
2
3
4
5
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
Object tokenHashedCredentials = this.hashProvidedCredentials(token, info);
Object accountCredentials = this.getCredentials(info);
return this.equals(tokenHashedCredentials, accountCredentials);
}

hashProvidedCredentials()是对本次登录的token进行hash。

1
2
3
4
5
6
7
8
9
10
11
protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) {
Object salt = null;
if(info instanceof SaltedAuthenticationInfo) {
//从info中获取salt
salt = ((SaltedAuthenticationInfo)info).getCredentialsSalt();
} else if(this.isHashSalted()) {
salt = this.getSalt(token);
}
//对密码进行hash
return this.hashProvidedCredentials(token.getCredentials(), salt, this.getHashIterations());
}

这里需要注意的是,在你的Realm中doGetAuthenticationInfo()返回的必须是SaltedAuthenticationInfo。

此方法是数据库中存储的密码信息解码成SHA-512

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected Object getCredentials(AuthenticationInfo info) {
Object credentials = info.getCredentials();
byte[] storedBytes = this.toBytes(credentials);
if(credentials instanceof String || credentials instanceof char[]) {
if(this.isStoredCredentialsHexEncoded()) {
storedBytes = Hex.decode(storedBytes);
} else {
storedBytes = Base64.decode(storedBytes);
}
}
AbstractHash hash = this.newHashInstance();
hash.setBytes(storedBytes);
return hash;
}