ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Authenticator

2021-11-15 22:34:10  阅读:250  来源: 互联网

标签:realm Authenticator token realms msg Realm 鉴权


简介

负责应用程序中用户鉴权操作;

通常为应用程序配置一个主身份验证器,通过主身份验证器协调配置的一组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);
            }
        }
    }
}

标签:realm,Authenticator,token,realms,msg,Realm,鉴权
来源: https://blog.csdn.net/xing_hung/article/details/121344577

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有