Spring Shiro基础组件 Authenticator

相关阅读

简介

负责应用程序中账户鉴权操作;
通常为应用程序配置一个主身份验证器,通过主身份验证器协调配置的一组Realm实现可插拔认证行为;

核心方法

/**
 * 基于提交的AuthenticationToken来鉴权
 */
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

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;
}

/**
 * 模板子方法,基于提交的AuthenticationToken来鉴权,由子类实现细节
 */
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;
}

/**
 * 基于提交的AuthenticationToken来鉴权
 */
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);
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值