Shiro 是如何完成密码的比对的呢?
我们已经知道,从页面传入的 username
及 password
已经被封装在 UsernamePasswordToken
实例中通过 Subject.login(AuthenticationToken)
方法交给了 Shiro 传递到了 LoginRealm
,而我们在 LoginRealm
中返回的校验信息是正确的用户名及密码信息。可以推断,Shiro 所做的比对其实就是将页面传入的 UsernamePasswordToken
实例和我们返回的正确的校验信息 AuthenticationInfo
实例中的数据进行比对,所以我们可以在返回 SimpleAuthenticationInfo
实例时打个断点,跟着进入源码,肯定能找到 Shiro 是如何完成比对。
下一步,进到调用 doGetAuthenticationInfo
的方法中:
// org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = getCachedAuthenticationInfo(token);
if (info == null) {
//otherwise not cached, perform the lookup:
// <1>
info = doGetAuthenticationInfo(token);
log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
if (token != null && info != null) {
cacheAuthenticationInfoIfPossible(token, info);
}
} else {
log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
}
if (info != null) {
// <2>
assertCredentialsMatch(token, info);
} else {
log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);
}
return info;
}
可以看到,在 <1>
处拿到我们返回的 SimpleAuthenticationInfo
实例,接着将 UsernamePasswordToken
实例和 SimpleAuthenticationInfo
实例一起传入 <2>
处的 assertCredentialsMatch(token, info)
方法:
// org.apache.shiro.realm.AuthenticatingRealm#assertCredentialsMatch
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
// <3>
if (!cm.doCredentialsMatch(token, info)) {
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
"credentials during authentication. If you do not wish for credentials to be examined, you " +
"can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
再看到 <3>
处的 cm.doCredentialsMatch(token, info)
方法,通过方法名就可以看出这是个凭证匹配的方法,依旧是将 UsernamePasswordToken
实例和 SimpleAuthenticationInfo
实例一起传入了:
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
Object tokenCredentials = getCredentials(token);
Object accountCredentials = getCredentials(info);
return equals(tokenCredentials, accountCredentials);
}
一目了然, 拿到页面传入的密码和正确的密码进行比对,返回布尔值。接着回到 org.apache.shiro.realm.AuthenticatingRealm#assertCredentialsMatch
方法中,如果比对失败,则抛出 org.apache.shiro.authc.AuthenticationException
异常。
总结:Shiro 是通过 org.apache.shiro.authc.credential.CredentialsMatcher
类实例的 doCredentialsMatch
方法来完成页面传入的密码和实际的密码的比对。
评论区