You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Spring Data Mongo Reactive与Spring Security 5下AuditorAware失效问题?

响应式Spring Boot中Mongo审计CreatedBy为空问题解决

你遇到的这个问题其实很典型——在响应式Spring应用里用传统的AuditorAware接口实现审计会失效,核心原因是ReactiveSecurityContextHolder的上下文是异步非阻塞的,你用blockOptional()强行阻塞获取值,会直接破坏响应式执行链,导致无法拿到当前请求的安全上下文,自然author字段就为空了。

问题原因拆解

传统的AuditorAware是为同步场景设计的,它的getCurrentAuditor()返回Optional<T>,但你在实现里调用blockOptional()会引发两个问题:

  • 响应式上下文的SecurityContext是绑定在当前请求的Reactor线程中的,强行阻塞会导致上下文丢失,根本拿不到正确的认证信息
  • createdDate能正常填充是因为日期是同步生成的,不需要依赖上下文,但CreatedBy对应的审计者信息依赖安全上下文,所以就成了null

解决方案

方案1:旧版本(Spring Boot < 2.4)的临时适配

在Spring Boot 2.4之前,Spring Data还没提供响应式审计接口,我们需要自己扩展适配:

  1. 先自定义一个响应式的审计者接口:
public interface ReactiveAuditorAware<T> {
    Mono<T> getCurrentAuditor();
}
  1. 实现这个接口,从ReactiveSecurityContextHolder中获取当前用户:
@Component
public class ReactiveSpringSecurityAuditorAware implements ReactiveAuditorAware<Username> {

    @Override
    public Mono<Username> getCurrentAuditor() {
        return ReactiveSecurityContextHolder.getContext()
                .map(SecurityContext::getAuthentication)
                .filter(authentication -> authentication != null && authentication.isAuthenticated())
                .map(Authentication::getPrincipal)
                .cast(UserDetails.class)
                .map(userDetails -> new Username(userDetails.getName()))
                .switchIfEmpty(Mono.empty());
    }
}
  1. 自定义响应式审计元数据生成器,替换默认同步实现:
@Configuration
@EnableMongoAuditing
public class ReactiveMongoAuditingConfiguration implements MongoAuditingConfiguration {

    private final ReactiveAuditorAware<Username> auditorAware;

    public ReactiveMongoAuditingConfiguration(ReactiveAuditorAware<Username> auditorAware) {
        this.auditorAware = auditorAware;
    }

    @Bean
    public ReactiveAuditingEntityCallback reactiveAuditingEntityCallback() {
        return new ReactiveAuditingEntityCallback(auditingHandler());
    }

    @Bean
    public AuditingHandler auditingHandler() {
        AuditingHandler handler = new AuditingHandler(MappingContext.getPersistentEntity());
        handler.setAuditorProvider(auditorProvider());
        return handler;
    }

    private AuditorAware<Username> auditorProvider() {
        return () -> auditorAware.getCurrentAuditor().blockOptional();
    }
}

注意:这里的blockOptional()是在审计回调的特定时机调用的,此时响应式上下文是可用的,不会像之前那样丢失。

方案2:新版本(Spring Boot ≥ 2.4.0-M2)的官方支持

从Spring Boot 2.4.0-M2(对应Spring Data Common 2.4.0-M2、Spring Data Mongo 3.1.0-M2)开始,官方已经提供了**ReactiveAuditorAware接口**,直接用就行,步骤更简单:

  1. 实现官方的ReactiveAuditorAware:
@Component
public class SpringSecurityReactiveAuditorAware implements ReactiveAuditorAware<Username> {

    @Override
    public Mono<Username> getCurrentAuditor() {
        return ReactiveSecurityContextHolder.getContext()
                .map(SecurityContext::getAuthentication)
                .filter(auth -> auth != null && auth.isAuthenticated())
                .map(Authentication::getPrincipal)
                .cast(UserDetails.class)
                .map(user -> new Username(user.getName()));
    }
}
  1. 启用响应式Mongo审计,把原来的@EnableMongoAuditing换成@EnableReactiveMongoAuditing:
@SpringBootApplication
@EnableReactiveMongoAuditing
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}

配置完成后,Spring Data Mongo会自动识别ReactiveAuditorAware的Bean,正确从响应式安全上下文中获取审计者信息,CreatedBy字段就能正常填充了。

验证效果

重启应用后,新增帖子的返回数据应该会包含正确的author信息:

{"id":"5a49ccdb9222971f40a4ada1","title":"my first post","content":"content of my first post","createdDate":"2018-01-01T13:53:31.234","author":{"name":"your-username"}}

内容的提问来源于stack exchange,提问作者Hantsy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:47:01