Spring Security API: ProviderManager

ProviderManager

Declared

package org.springframework.security.authentication;
public class ProviderManager
implements AuthenticationManager, MessageSourceAware, InitializingBean

Class JDOC

通过遍历AuthenticationProvider列表处理Authentication请求。

通常按顺序尝试Authenticationprovider,直到其中一个提供非空响应。非空响应意味着当前AuthenticationProvider有能力处理Authentication请求,且不再尝试其他AuthenticationProvider。如果后续AuthenticationProvider成功地对请求进行身份认证,则将忽略前面的身份认证异常,并使用成功的身份认证。如果后续AuthenticationProvider没有提供非空响应或新的AuthenticationException,则将使用接收到的最后一个AuthenticationException。如果没有AuthenticationProvider返回非空响应,或者表明它可以处理身份认证,ProviderManager将抛出ProviderNotFoundException。如果配置的提供程序都不能执行身份验证,还可以尝试设置父AuthenticationManager。这是为了支持名称空间配置选项,而不是通常需要的功能。

此过程的异常是当提供者抛出AccountStatusException时,在这种情况下,列表中的其他提供者将不再被查询。身份验证后,如果返回的Authentication对象实现了CredentialsContainer接口,则将从该对象清除凭据。可以通过修改eraseCredentialsAfterAuthentication属性来控制这种行为。

事件发布

身份验证事件发布被委托给配置的AuthenticationEventPublisher,后者默认为不发布事件的空实现,所以如果您希望接收事件,就必须注入您自己的AuthenticationEventPublisher bean。标准实现是DefaultAuthenticationEventPublisher,它将常见异常映射到事件(在身份验证失败的情况下),并在身份验证成功时发布AuthenticationSuccessEvent。如果使用名称空间,则此bean的实例将由配置自动使用,因此您将自动从应用程序的web部分接收事件。

注意,当实现从设置好的“父”AuthenticationManager获取认证结果(或者异常)时发布认证失败异常。在这种情况下,“父”不应该在配置为发布事件或将会有重复

Method authenticate

Declared

public Authentication authenticate(Authentication authentication) throws AuthenticationException

Method JDOC

尝试对Authentication执行身份认证。

AuthenticationProvider列表将被依次尝试,直到某个AuthenticationProvider表明它能够对传递的Authentication对象的类型进行身份验证。然后将尝试使用该AuthenticationProvider进行身份验证。

如果有多个AuthenticationProvider支持所传递的Authentication对象,则第一个能够成功验证Authentication对象的对象将确定结果,并覆盖以前支持的AuthenticationProvider所抛出的任何可能的AuthenticationException。成功验证后,将不再尝试后续的AuthenticationProvider。如果任何支持的AuthenticationProvider都没有成功进行身份验证,则会重新抛出最后抛出的AuthenticationException。

Method Code

public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
    Class<? extends Authentication> toTest = authentication.getClass();
    AuthenticationException lastException = null;
    AuthenticationException parentException = null;
    Authentication result = null;
    Authentication parentResult = null;
    boolean debug = logger.isDebugEnabled();

    //遍历AuthenticationProvider列表
    for (AuthenticationProvider provider : getProviders()) {
        //判断此AuthenticationProvider能否对传递的Authentication对象的类型进行身份验证
        if (!provider.supports(toTest)) {
            continue;
        }

        if (debug) {
            logger.debug("Authentication attempt using "
                    + provider.getClass().getName());
        }


        try {
            //尝试使用该AuthenticationProvider进行身份验证
            result = provider.authenticate(authentication);

            if (result != null) {
                copyDetails(authentication, result);
                break;
            }
        }
        catch (AccountStatusException | InternalAuthenticationServiceException e) {
            prepareException(e, authentication);
            // SEC-546: Avoid polling additional providers if auth failure is due to
            // invalid account status
            // 无效的账户状态
            throw e;
        } catch (AuthenticationException e) {
            lastException = e;
        }
    }

    if (result == null && parent != null) {
        // Allow the parent to try.
        // 允许“父”尝试进行认证
        try {
            result = parentResult = parent.authenticate(authentication);
        }
        catch (ProviderNotFoundException e) {
            // ignore as we will throw below if no other exception occurred prior to
            // calling parent and the parent
            // may throw ProviderNotFound even though a provider in the child already
            // handled the request
            //如果在调用父类之前没有发生其他异常,父类可能会抛出ProviderNotFound,即使子类中的提供者已经处理了请求,我们将在下面抛出忽略
        }
        catch (AuthenticationException e) {
            lastException = parentException = e;
        }
    }

    if (result != null) {
        if (eraseCredentialsAfterAuthentication
                && (result instanceof CredentialsContainer)) {
            // Authentication is complete. Remove credentials and other secret data
            // from authentication
            // 认证完成,从认证中移除凭证
            ((CredentialsContainer) result).eraseCredentials();
        }

        // If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent
        // 如果尝试了父AuthenticationManager并成功,则它将发布AuthenticationSuccessEvent
        // This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
        // 如果父AuthenticationManager已经发布了重复的AuthenticationSuccessEvent,则此检查将防止重复的AuthenticationSuccessEvent
        if (parentResult == null) {
            eventPublisher.publishAuthenticationSuccess(result);
        }
        return result;
    }

    // Parent was null, or didn't authenticate (or throw an exception).
    // “父”为空,或没有进行身份验证(或抛出异常)。
    if (lastException == null) {
        lastException = new ProviderNotFoundException(messages.getMessage(
                "ProviderManager.providerNotFound",
                new Object[] { toTest.getName() },
                "No AuthenticationProvider found for {0}"));
    }

    // If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent
    // 如果试图使用父AuthenticationManager并失败,则它将发布一个AbstractAuthenticationFailureEvent
    // This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
    // 如果父AuthenticationManager已经发布了重复的AbstractAuthenticationFailureEvent,则此检查可防止该事件重复发生
    if (parentException == null) {
        prepareException(lastException, authentication);
    }

    throw lastException;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值