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