简介
负责应用程序中用户鉴权操作;
通常为应用程序配置一个主身份验证器,通过主身份验证器协调配置的一组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
简介
详见SecurityManager;
核心代码
无
-
AbstractAuthenticator
简介
模板模式实现了鉴权的算法框架,将真正鉴权尝试委托给子类实现;
支持登录成功/失败以及登出操作的通知,以便当这些条件发生时,进行定制化逻辑处理;
核心代码
// 鉴权监听器集合
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;
-
ModularRealmAuthenticator
简介
由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);
}
}
}
}