我正在使用Spring Security Oauth2来保护我的Spring Boot REST应用程序。我想在用户登录成功和失败后处理一些操作。问题是每一个
时间我发送带有用户承载令牌的请求,即使用户已经过身份验证,也会发布AuthenticationSuccessEvent
。
始终调用此处理程序:
@Async
@EventListener( { AuthenticationSuccessEvent.class } )
public void listenAuthenticationSuccessEvent( AuthenticationSuccessEvent event ) {
AbstractAuthenticationToken auth = (AbstractAuthenticationToken) event
.getSource();
log.info( "User connected: {}", auth.getName() );
}
这是正常的吗?我希望它被召唤一次。
寻求帮助
答案 0 :(得分:1)
默认情况下(从Spring 5.x开始)在每个令牌/ refresh_token上调用 AuthenticationSuccessEvent 事件的原因是“授权:基本的clientID:clientSecret” 标头作为令牌请求的一部分出现,因此由 BasicAuthenticationFilter 处理的请求以及使用相应的 AuthenticationManager(ProviderManager)(除了 ProviderManager em>负责令牌auth)的实现。
每个 ProviderManager 依次具有 AuthenticationEventPublisher 依赖性,该依赖性用于发布各种事件,在我们的案例中(验证成功),它是 eventPublisher .publishAuthenticationSuccess(result);
默认情况下, ProviderManager 使用 NullEventPublisher ,可以使用 ProviderManager#setAuthenticationEventPublisher setter覆盖。
ProviderManager 由'AuthenticationManagerBuilder 创建,并为其设置了相应的事件发布者(如果不为null)。
protected ProviderManager performBuild() throws Exception {
...
ProviderManager providerManager = new ProviderManager(authenticationProviders,
parentAuthenticationManager);
...
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
AuthenticationManagerBuilder是从 WebSecurityConfigurerAdapter 填充的,请参见 WebSecurityConfigurerAdapter#getHttp 方法,您可以在其中找到以下行(在Spring Security 5.x中添加):
authenticationBuilder.authenticationEventPublisher(eventPublisher);
覆盖默认行为的一种方法是实现相应的BasicWebSecurityConfig(扩展WebSecurityConfigurerAdapter或AuthorizationServerSecurityConfiguration),并在创建 ProviderManager 之前将NullEventPublisher设置为'AuthenticationManagerBuilder :>
@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) {
}
}
}