问题
I am using Spring Security Oauth2 to secure my Spring Boot REST app. I want to process some operation after a user login success and failure. The problem is each
time I send a request with the user bearer token, AuthenticationSuccessEvent
is published even the user is already authenticated.
This handler is always called:
@Async
@EventListener( { AuthenticationSuccessEvent.class } )
public void listenAuthenticationSuccessEvent( AuthenticationSuccessEvent event ) {
AbstractAuthenticationToken auth = (AbstractAuthenticationToken) event
.getSource();
log.info( "User connected: {}", auth.getName() );
}
Is it normal? I want it to be called once.
Thans for your help
回答1:
The reason that AuthenticationSuccessEvent event is being called on every token/refresh_token by default (starting from Spring 5.x) is because "Authorization: Basic clientID:clientSecret" header is presented as part of token request thus request handled by BasicAuthenticationFilter as well that authenticates the client using corresponding AuthenticationManager(ProviderManager) (in addition to the ProviderManager that is responsible for the token auth) implementation.
Each ProviderManager, in turn, has AuthenticationEventPublisher dependency that is used for publishing different kinds of events, in our case(auth success), it is eventPublisher.publishAuthenticationSuccess(result);
By default ProviderManager uses NullEventPublisher that could be overridden using ProviderManager#setAuthenticationEventPublisher setter.
ProviderManager is created by 'AuthenticationManagerBuilder that set corresponding event publisher to it(if not null).
protected ProviderManager performBuild() throws Exception {
...
ProviderManager providerManager = new ProviderManager(authenticationProviders,
parentAuthenticationManager);
...
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
AuthenticationManagerBuilder is populated from WebSecurityConfigurerAdapter see WebSecurityConfigurerAdapter#getHttp method where you cand find the following line(that was added in Spring Security 5.x):
authenticationBuilder.authenticationEventPublisher(eventPublisher);
One of the approaches to override that default behavior is to implement corresponding BasicWebSecurityConfig(extending WebSecurityConfigurerAdapter or AuthorizationServerSecurityConfiguration) and set NullEventPublisher to the 'AuthenticationManagerBuilder before ProviderManager creation:
@Configuration
@Order(-1)
public class BasicSecurityConfiguration extends AuthorizationServerSecurityConfiguration {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
// override default DefaultAuthenticationEventPublisher to avoid excessive firing of
// AuthenticationSuccessEvent on successful client credentials verification that passed in "Authorization: Basic clientId:clientSecret" header
http.getSharedObject(AuthenticationManagerBuilder.class).authenticationEventPublisher(new NullEventPublisher());
http.httpBasic()
}
private static final class NullEventPublisher implements AuthenticationEventPublisher {
public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
}
public void publishAuthenticationSuccess(Authentication authentication) {
}
}
}
来源:https://stackoverflow.com/questions/50663431/spring-security-oauth2-authenticationsuccessevent-published-at-each-request