For each authentication that succeeds or fails, a AuthenticationSuccessEvent
or AuthenticationFailureEvent
, respectively, is fired.
To listen for these events, you must first publish an AuthenticationEventPublisher
.
Spring Security’s DefaultAuthenticationEventPublisher
works fine for this purpose:
- Java
-
@Bean public AuthenticationEventPublisher authenticationEventPublisher (ApplicationEventPublisher applicationEventPublisher) { return new DefaultAuthenticationEventPublisher(applicationEventPublisher); }
- Kotlin
-
@Bean fun authenticationEventPublisher (applicationEventPublisher: ApplicationEventPublisher?): AuthenticationEventPublisher { return DefaultAuthenticationEventPublisher(applicationEventPublisher) }
Then you can use Spring’s @EventListener
support:
- Java
-
@Component public class AuthenticationEvents { @EventListener public void onSuccess(AuthenticationSuccessEvent success) { // ... } @EventListener public void onFailure(AbstractAuthenticationFailureEvent failures) { // ... } }
- Kotlin
-
@Component class AuthenticationEvents { @EventListener fun onSuccess(success: AuthenticationSuccessEvent?) { // ... } @EventListener fun onFailure(failures: AbstractAuthenticationFailureEvent?) { // ... } }
While similar to AuthenticationSuccessHandler
and AuthenticationFailureHandler
, these are nice in that they can be used independently from the servlet API.
By default, DefaultAuthenticationEventPublisher
publishes an AuthenticationFailureEvent
for the following events:
Exception |
Event |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The publisher does an exact Exception
match, which means that sub-classes of these exceptions do not also produce events.
To that end, you may want to supply additional mappings to the publisher through the setAdditionalExceptionMappings
method:
- Java
-
@Bean public AuthenticationEventPublisher authenticationEventPublisher (ApplicationEventPublisher applicationEventPublisher) { Map<Class<? extends AuthenticationException>, Class<? extends AbstractAuthenticationFailureEvent>> mapping = Collections.singletonMap(FooException.class, FooEvent.class); DefaultAuthenticationEventPublisher authenticationEventPublisher = new DefaultAuthenticationEventPublisher(applicationEventPublisher); authenticationEventPublisher.setAdditionalExceptionMappings(mapping); return authenticationEventPublisher; }
- Kotlin
-
@Bean fun authenticationEventPublisher (applicationEventPublisher: ApplicationEventPublisher?): AuthenticationEventPublisher { val mapping: Map<Class<out AuthenticationException>, Class<out AbstractAuthenticationFailureEvent>> = mapOf(Pair(FooException::class.java, FooEvent::class.java)) val authenticationEventPublisher = DefaultAuthenticationEventPublisher(applicationEventPublisher) authenticationEventPublisher.setAdditionalExceptionMappings(mapping) return authenticationEventPublisher }
You can also supply a catch-all event to fire in the case of any AuthenticationException
:
- Java
-
@Bean public AuthenticationEventPublisher authenticationEventPublisher (ApplicationEventPublisher applicationEventPublisher) { DefaultAuthenticationEventPublisher authenticationEventPublisher = new DefaultAuthenticationEventPublisher(applicationEventPublisher); authenticationEventPublisher.setDefaultAuthenticationFailureEvent (AbstractAuthenticationFailureEvent.class); return authenticationEventPublisher; }
- Kotlin
-
@Bean fun authenticationEventPublisher (applicationEventPublisher: ApplicationEventPublisher?): AuthenticationEventPublisher { val authenticationEventPublisher = DefaultAuthenticationEventPublisher(applicationEventPublisher) authenticationEventPublisher.setDefaultAuthenticationFailureEvent(AbstractAuthenticationFailureEvent::class.java) return authenticationEventPublisher }