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