如何解决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还没提供响应式审计接口,我们需要自己扩展适配:
- 先自定义一个响应式的审计者接口:
public interface ReactiveAuditorAware<T> { Mono<T> getCurrentAuditor(); }
- 实现这个接口,从
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()); } }
- 自定义响应式审计元数据生成器,替换默认同步实现:
@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接口**,直接用就行,步骤更简单:
- 实现官方的
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())); } }
- 启用响应式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
相关产品推荐
相关产品推荐

