# Spring Security AuthenticationEventPublisher

接口类AuthenticationEventPublisher定义了Spring Security中用户授权成功或失败的通知机制. 方法:

//成功时调用
void publishAuthenticationSuccess(Authentication authentication);
//失败时调用
void publishAuthenticationFailure(AuthenticationException exception,
            Authentication authentication);

并且提供了一个默认的实现策略类DefaultAuthenticationEventPublisher,同时实现了接口类AuthenticationEventPublisher,ApplicationEventPublisherAware DefaultAuthenticationEventPublisher在其内部维护一个异常类AuthenticationException和其对应的事件类AbstractAuthenticationFailureEvent的哈希表,方便将异常同授权事件对应起来. (“成功的原因大都相似,失败的原因各种各样”)

//构造函数中初始化
addMapping(BadCredentialsException.class.getName(),AuthenticationFailureBadCredentialsEvent.class);
addMapping(UsernameNotFoundException.class.getName(),AuthenticationFailureBadCredentialsEvent.class);
addMapping(AccountExpiredException.class.getName(),AuthenticationFailureExpiredEvent.class);

授权成功时发布事件

applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent(authentication));

失败时

Constructor<? extends AbstractAuthenticationEvent> constructor = exceptionMappings.get(exception.getClass().getName());
AbstractAuthenticationEvent event = null;
if (constructor != null) {
    try {
        event = constructor.newInstance(authentication, exception);
    } catch () {
    }
}
if (event != null) {
    if (applicationEventPublisher != null) {
        applicationEventPublisher.publishEvent(event);
    }
}

参照测试类DefaultAuthenticationEventPublisherTests可以理解其使用逻辑

publisher = new DefaultAuthenticationEventPublisher();
ApplicationEventPublisher appPublisher = mock(ApplicationEventPublisher.class);
publisher.setApplicationEventPublisher(appPublisher);
Authentication a = mock(Authentication.class);

Exception cause = new Exception();
Object extraInfo = new Object();
publisher.publishAuthenticationFailure(new BadCredentialsException(""), a);
publisher.publishAuthenticationFailure(new BadCredentialsException("", cause), a);
verify(appPublisher, times(2)).publishEvent(isA(AuthenticationFailureBadCredentialsEvent.class));