ModularRealmAuthenticator 的源碼分析和配置
複製代碼
SecurityManager獲得token信息後,經過調用authenticator.authenticate(token)方法,把身份驗證委託給內置的Authenticator的實例進行驗證。authenticator一般是ModularRealmAuthenticator 實例,支持對一個或多個Realm實例進行適配。ModularRealmAuthenticator提供了一種可插拔的認證風格,你能夠在此處插入自定義Realm實現。markdown
若是配置了多個Realm,ModularRealmAuthenticator會根據配置的AuthenticationStrategy(身份驗證策略)進行多Realm認證過程。 注:若是應用程序中僅配置了一個Realm,Realm將被直接調用而無需再配置認證策略。app
判斷每一個Realm是否支持提交的token,若是支持Realm就會調用getAuthenticationInfo(token)方法進行認證處理。 AuthenticationStrategy(身份驗證策略)會在後邊講解ide
public abstract class AbstractAuthenticator implements Authenticator, LogoutAware {
public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
if (token == null) {
throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
}
log.trace("Authentication attempt received for token [{}]", token);
AuthenticationInfo info;
try {
*// 調用 ModularRealmAuthenticator。 doAuthenticate(token) 方法*
info = doAuthenticate(token);
if (info == null) {
String msg = "No account information found for authentication token [" + token + "] by this " +
"Authenticator instance. Please check that it is configured correctly.";
throw new AuthenticationException(msg);
}
} catch (Throwable t) {
AuthenticationException ae = null;
if (t instanceof AuthenticationException) {
ae = (AuthenticationException) t;
}
if (ae == null) {
//Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more
//severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate:
String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " +
"error? (Typical or expected login exceptions should extend from AuthenticationException).";
ae = new AuthenticationException(msg, t);
if (log.isWarnEnabled())
log.warn(msg, t);
}
try {
notifyFailure(token, ae);
} catch (Throwable t2) {
if (log.isWarnEnabled()) {
String msg = "Unable to send notification for failed authentication attempt - listener error?. " +
"Please check your AuthenticationListener implementation(s). Logging sending exception " +
"and propagating original AuthenticationException instead...";
log.warn(msg, t2);
}
}
throw ae;
}
log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info);
notifySuccess(token, info);
return info;
}
protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token)
throws AuthenticationException;
}
複製代碼
ModularRealmAuthenticator 源碼分析源碼分析
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
}
複製代碼
①當realm==1的時候
複製代碼
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
if (!realm.supports(token)) {
String msg = "Realm [" + realm + "] does not support authentication token [" +
token + "]. Please ensure that the appropriate Realm implementation is " +
"configured correctly or that the realm accepts AuthenticationTokens of this type.";
throw new UnsupportedTokenException(msg);
}
// 去調用自定義realm 中的認證方法
AuthenticationInfo info = realm.getAuthenticationInfo(token);
if (info == null) {
String msg = "Realm [" + realm + "] was unable to find account data for the " +
"submitted AuthenticationToken [" + token + "].";
throw new UnknownAccountException(msg);
}
return info;
}
}
複製代碼
當realm個數大於1 的時候 realms!=1 這裏會涉及到>AuthenticationStrategy(身份驗證策略)post
根據策略進行認證結果ui
public class ModularRealmAuthenticator extends AbstractAuthenticator {
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
// 得到認證策略
AuthenticationStrategy strategy = getAuthenticationStrategy();
AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
if (log.isTraceEnabled()) {
log.trace("Iterating through {} realms for PAM authentication", realms.size());
}
for (Realm realm : realms) {
aggregate = strategy.beforeAttempt(realm, token, aggregate);
if (realm.supports(token)) {
log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);
AuthenticationInfo info = null;
Throwable t = null;
try {
info = realm.getAuthenticationInfo(token);
} catch (Throwable throwable) {
t = throwable;
if (log.isDebugEnabled()) {
String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
log.debug(msg, t);
}
}
aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
} else {
log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token);
}
}
aggregate = strategy.afterAllAttempts(token, aggregate);
return aggregate;
}
}
複製代碼
// 去調用自定義realm 中的認證方法this
AuthenticationInfo info = realm.getAuthenticationInfo(token);
多realm 就是for循環調用 getAuthenticationInfo(token);
複製代碼
public class MyRealm extends AuthorizingRealm {
//public class MyRealm extends AuthenticatingRealm {
/**
* 認證
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = String.valueOf(usernamePasswordToken.getPassword());
ByteSource solt = ByteSource.Util.bytes(username);
if (username.equals("username") && password.equals("password")) {
return new SimpleAuthenticationInfo(username, password, getName());
}
return null;
}
}
複製代碼
進行密碼比較url
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
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.");
}
}
}
複製代碼