自定义ReactiveAuthenticationManager后Spring Boot Actuator审计事件无数据求助
这个问题我之前也碰到过,核心原因是自定义的ReactiveAuthenticationManager不会自动触发Spring Security的审计事件发布逻辑——默认的认证管理器(比如UserDetailsRepositoryReactiveAuthenticationManager)内部已经集成了事件发布的处理,但自定义实现时需要我们手动补上这部分逻辑。下面是具体的解决步骤和代码示例:
一、核心原理
Spring Security的审计事件(比如认证成功/失败事件)是通过AuthenticationEventPublisher接口来发布的,Actuator的auditevents端点会收集这些事件并返回。自定义认证管理器时,我们需要主动调用这个发布器来触发事件。
二、解决方案1:在自定义认证管理器中手动发布事件
直接在你的CustomReactiveAuthenticationManager中注入AuthenticationEventPublisher,在认证成功或失败时发布对应事件:
@Component public class CustomReactiveAuthenticationManager implements ReactiveAuthenticationManager { private final AuthenticationEventPublisher authenticationEventPublisher; // 构造注入事件发布器 public CustomReactiveAuthenticationManager(AuthenticationEventPublisher authenticationEventPublisher) { this.authenticationEventPublisher = authenticationEventPublisher; } @Override public Mono<Authentication> authenticate(Authentication authentication) { // 这里替换成你的实际认证逻辑 return Mono.just(authentication) .flatMap(auth -> { // 模拟认证成功场景 if ("valid-user".equals(auth.getName()) && "correct-pass".equals(auth.getCredentials())) { UsernamePasswordAuthenticationToken authenticatedToken = new UsernamePasswordAuthenticationToken(auth.getName(), null, Collections.emptyList()); // 发布认证成功事件 authenticationEventPublisher.publishAuthenticationSuccess(authenticatedToken); return Mono.just(authenticatedToken); } else { // 模拟认证失败场景 BadCredentialsException exception = new BadCredentialsException("Invalid username or password"); // 发布认证失败事件 authenticationEventPublisher.publishAuthenticationFailure(exception, authentication); return Mono.error(exception); } }); } }
三、解决方案2:用ReactiveAuthenticationManagerDecorator包装(更简洁)
如果不想在自定义管理器里写事件发布逻辑,可以用Spring提供的ReactiveAuthenticationManagerDecorator包装你的自定义管理器,它会自动处理事件发布:
@Bean public ReactiveAuthenticationManager decoratedAuthenticationManager( CustomReactiveAuthenticationManager customAuthManager, AuthenticationEventPublisher eventPublisher) { return new ReactiveAuthenticationManagerDecorator(customAuthManager, eventPublisher); }
然后在SecurityWebFilterChain中使用这个包装后的认证管理器:
@Bean public SecurityWebFilterChain securityWebFilterChain( ServerHttpSecurity http, ReactiveAuthenticationManager decoratedAuthenticationManager) { return http .authorizeExchange(exchanges -> exchanges .pathMatchers("/actuator/auditevents").permitAll() // 根据你的权限需求调整 .anyExchange().authenticated() ) .authenticationManager(decoratedAuthenticationManager) .build(); }
四、确保Actuator端点配置正确
最后要确认Actuator的auditevents端点已启用并可访问,在application.yml中添加:
management: endpoints: web: exposure: include: auditevents # 暴露auditevents端点 endpoint: auditevents: enabled: true # 启用该端点
完成以上配置后,再进行认证操作,访问/actuator/auditevents就能看到对应的审计事件了。
内容的提问来源于stack exchange,提问作者user3139545

