AuthenticationManagerBuilder
继承了之前提到的AbstractConfiguredSecurityBuilder构造器
postProcess安全对象的后处理,那么ProviderManager是什么
ProviderManager
Authentication
public interface Authentication extends Principal, Serializable {
/**
** 权限
*/
Collection<? extends GrantedAuthority> getAuthorities();
/**
** 凭证,用户名/密码登陆方式密码就是凭证
*/
Object getCredentials();
/**
** 存放ip或者证书序列号
*/
Object getDetails();
/**
* 要进行身份验证的主体的身份。对于带有用户名和密码的身份验证请求,这将是用户名。调用方应填充身份验证请求的主体
*/
Object getPrincipal();
/**
* 判断是否被认证
*/
boolean isAuthenticated();
/**
* 设置authenticated属性
*/
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
AuthenticationProvider
策略模式典型实现
认证登录不仅仅是账户密码登录,还可能是QQ、微信登录等
之后新增只需要新继承这个Provider即可,符合开闭模式,保证只新增代码,不修改以往代码
public interface AuthenticationProvider {
/**
* 使用与 AuthenticationManager.authenticate(Authentication) 相同的协定执行身份验证。
* 完全经过身份验证的对象,包括凭据。
*/
Authentication authenticate(Authentication authentication) throws AuthenticationException;
/**
* 如果这AuthenticationProvider支持指示Authentication的对象,则返回true。
*/
boolean supports(Class<?> authentication);
}
AuthenticationManager
public interface AuthenticationManager {
/**
* Attempts to authenticate the passed {@link Authentication} object, returning a
* fully populated <code>Authentication</code> object (including granted authorities)
* if successful.
* <p>
* An <code>AuthenticationManager</code> must honour the following contract concerning
* exceptions:
* <ul>
* <li>A {@link DisabledException} must be thrown if an account is disabled and the
* <code>AuthenticationManager</code> can test for this state.</li>
* <li>A {@link LockedException} must be thrown if an account is locked and the
* <code>AuthenticationManager</code> can test for account locking.</li>
* <li>A {@link BadCredentialsException} must be thrown if incorrect credentials are
* presented. Whilst the above exceptions are optional, an
* <code>AuthenticationManager</code> must <B>always</B> test credentials.</li>
* </ul>
*尝试对传递 Authentication 的对象进行身份验证,如果成功,则返回完全填充的 Authentication 对象
*必须 AuthenticationManager 履行以下有关例外情况的合同:
* 如果帐户被禁用,AuthenticationManager则必须抛出 ADisabledException,并且可以测试此状态。
* 如果帐户被锁定,AuthenticationManager则必须抛出 ALockedException,并且可以测试帐户锁定。
* 如果提供不正确的凭据,则必须抛出 A BadCredentialsException 。虽然上述例外是可选的, AuthenticationManager 但必须 始终 测试凭据。
*/
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
关键属性
// 事件发布器
private AuthenticationEventPublisher eventPublisher = new NullEventPublisher();
// 之前说的策略,用自己授权
private List<AuthenticationProvider> providers = Collections.emptyList();
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
// 父类,使用父类授权
private AuthenticationManager parent;
private boolean eraseCredentialsAfterAuthentication = true;
@Override
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;
int currentPosition = 0;
int size = this.providers.size();
// 循环认证
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
if (logger.isTraceEnabled()) {
logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
provider.getClass().getSimpleName(), ++currentPosition, size));
}
try {
result = provider.authenticate(authentication);
if (result != null) {
/**
** 存放ip或者证书序列号
*/
// Object getDetails();
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException | InternalAuthenticationServiceException ex) {
prepareException(ex, authentication);
throw ex;
}
catch (AuthenticationException ex) {
lastException = ex;
}
}
// 找不到对应的Authentication,则调用父类的授权
if (result == null && this.parent != null) {
try {
parentResult = this.parent.authenticate(authentication);
result = parentResult;
}
catch (ProviderNotFoundException ex) {
}
catch (AuthenticationException ex) {
parentException = ex;
lastException = ex;
}
}
if (result != null) {
// 擦除凭证信息
if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
((CredentialsContainer) result).eraseCredentials();
}
if (parentResult == null) {
this.eventPublisher.publishAuthenticationSuccess(result);
}
return result;
}
if (lastException == null) {
lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",
new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));
}
if (parentException == null) {
prepareException(lastException, authentication);
}
throw lastException;
}