Spring Security Oauth2 AuthenticationSuccessEvent published at each request

不问归期 提交于 2020-03-20 03:54:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!