负责应用程序中用户鉴权操作;
通常为应用程序配置一个主身份验证器,通过主身份验证器协调配置的一组Realm,实现可插拔认证行为;
/** * 鉴权 */ public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException;
实现类如下:
public interface Authenticator public interface SecurityManager extends Authenticator, Authorizer, SessionManager public abstract class AbstractAuthenticator implements Authenticator, LogoutAware public class ModularRealmAuthenticator extends AbstractAuthenticator
详见SecurityManager;
无
模板模式实现了鉴权的算法框架,将真正鉴权尝试委托给子类实现;
支持登录成功/失败以及登出操作的通知,以便当这些条件发生时,进行定制化逻辑处理;
// 鉴权监听器集合 private Collection<AuthenticationListener> listeners; /** * 通知成功事件 */ protected void notifySuccess(AuthenticationToken token, AuthenticationInfo info) { for (AuthenticationListener listener : this.listeners) { listener.onSuccess(token, info); } } /** * 通知失败事件 */ protected void notifyFailure(AuthenticationToken token, AuthenticationException ae) { for (AuthenticationListener listener : this.listeners) { listener.onFailure(token, ae); } } /** * 通知登出事件 */ protected void notifyLogout(PrincipalCollection principals) { for (AuthenticationListener listener : this.listeners) { listener.onLogout(principals); } } /** * 登出 */ public void onLogout(PrincipalCollection principals) { // 通知监听器登出事件 notifyLogout(principals); } /** * 鉴权 * 算法模板,基于AuthenticationToken鉴权的算法框架 */ 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 { // 根据提交的token匹配查找系统中存储的AuthenticationInfo,由子类实现算法细节 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); // 返回AuthenticationInfo信息 return info; } /** * 鉴权 * 模板子方法,由子类实现算法细节 */ protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException;
由Realm集合实现鉴权;
该类实现了可插拔认证行为,即通过Realm集合和AuthenticationStrategy实现灵活认证控制;
如果只有一个Realm,那么就等价于Realm.getAuthenticationInfo(AuthenticationToken);
如果有多个Realm,便遍历所有的Realm,根据AuthenticationStrategy决定执行策略:
一个Realm验证成功;
全部Realm验证成功;
其他;
// Realm集合,动态增删Realm是实现可插拔鉴权的基础 private Collection<Realm> realms; // 鉴权策略,多Realm场景有效,和Realm集合一起实现鉴权 private AuthenticationStrategy authenticationStrategy; /** * 构造方法 */ public ModularRealmAuthenticator() { // 默认采用AtLeastOneSuccessfulStrategy this.authenticationStrategy = new AtLeastOneSuccessfulStrategy(); } /** * 校验配置的Realm集合的有效性 */ protected void assertRealmsConfigured() throws IllegalStateException { Collection<Realm> realms = getRealms(); if (CollectionUtils.isEmpty(realms)) { String msg = "Configuration error: No realms have been configured! One or more realms must be " + "present to execute an authentication attempt."; throw new IllegalStateException(msg); } } /** * 单Realm场景下的鉴权 */ protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { if (!realm.supports(token)) { // 不支持该类型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); } // 根据提交的token匹配查找系统中存储的AuthenticationInfo 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场景下的鉴权 */ 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()); } // 遍历Realm集合 for (Realm realm : realms) { try { // 本次鉴权的预处理 aggregate = strategy.beforeAttempt(realm, token, aggregate); } catch (ShortCircuitIterationException shortCircuitSignal) { // Break from continuing with subsequnet realms on receiving // short circuit signal from strategy break; } // 校验该Realm是否支持该类型token if (realm.supports(token)) { log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm); AuthenticationInfo info = null; Throwable t = null; try { // 根据提交的token匹配查找系统中存储的AuthenticationInfo 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; } /** * 鉴权 */ protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { // 校验Realm集合的有效性 assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { // 单Realm return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { // 多Realm return doMultiRealmAuthentication(realms, authenticationToken); } } /** * 登出 */ public void onLogout(PrincipalCollection principals) { // 调用父类,通知监听器登出事件 super.onLogout(principals); Collection<Realm> realms = getRealms(); if (!CollectionUtils.isEmpty(realms)) { // 遍历Realm集合 for (Realm realm : realms) { if (realm instanceof LogoutAware) { // 执行登出处理 ((LogoutAware) realm).onLogout(principals); } } } }