如何使 AuditorAware 与 Spring Data Mongo Reactive 一起使用
Posted
技术标签:
【中文标题】如何使 AuditorAware 与 Spring Data Mongo Reactive 一起使用【英文标题】:How to make AuditorAware work with Spring Data Mongo Reactive 【发布时间】:2018-06-11 08:42:36 【问题描述】:Spring Security 5 提供了一个ReactiveSecurityContextHolder
to fetch the SecurityContext
from a Reactive context,但是当我想实现AuditorAware
并自动获得试听工作时,它不起作用。 目前我找不到AuditorAware
的Reactive
变体。
@Bean
public AuditorAware<Username> auditor()
return () -> ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.log()
.filter(a -> a != null && a.isAuthenticated())
.map(Authentication::getPrincipal)
.cast(UserDetails.class)
.map(auth -> new Username(auth.getName()))
.switchIfEmpty(Mono.empty())
.blockOptional();
我已经在我的引导Application
类中添加了@EnableMongoAuduting
。
在 Mongo 文档类上。我添加了试听相关的注释。
@CreatedDate
private LocalDateTime createdDate;
@CreatedBy
private Username author;
当我添加一个帖子时,createdDate
已填充,但作者为空。
"id":"5a49ccdb9222971f40a4ada1","title":"my first post","content":"content of my first post","createdDate":"2018-01-01T13:53:31.234","author":null
完整代码为here,基于Spring Boot 2.0.0.M7。
更新: Spring Boot 2.4.0-M2/Spring Data Common 2.4.0-M2/Spring Data Mongo 3.1.0-M2 包括ReactiveAuditorAware
,检查this new sample,注意:使用@EnableReactiveMongoAuditing
来激活它。
【问题讨论】:
尚无对反应性使用的审核支持。 【参考方案1】:已弃用:查看原帖中的更新解决方案
在提供官方 reactive AuditAware 之前,有一个替代方案可以通过 Spring Data Mongo 特定的ReactiveBeforeConvertCallback
来实现这些。
-
不要使用
@EnableMongoAuditing
实现自己的ReactiveBeforeConvertCallback
,这里我为那些需要审计的实体使用PersistentEntity
接口。
public class PersistentEntityCallback implements ReactiveBeforeConvertCallback<PersistentEntity>
@Override
public Publisher<PersistentEntity> onBeforeConvert(PersistentEntity entity, String collection)
var user = ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.filter(it -> it != null && it.isAuthenticated())
.map(Authentication::getPrincipal)
.cast(UserDetails.class)
.map(userDetails -> new Username(userDetails.getUsername()))
.switchIfEmpty(Mono.empty());
var currentTime = LocalDateTime.now();
if (entity.getId() == null)
entity.setCreatedDate(currentTime);
entity.setLastModifiedDate(currentTime);
return user
.map(u ->
if (entity.getId() == null)
entity.setCreatedBy(u);
entity.setLastModifiedBy(u);
return entity;
)
.defaultIfEmpty(entity);
查看完整代码here。
【讨论】:
如果代码支持通过相同的端点和数据库保存方法插入/更新,这可能不起作用。如果有人会发送一个带有 id 的 DTO,该 DTO 将被映射到一个构造的 DOCUMENT 中并且它不存在于数据库中,那么所有依赖于 id 的字段都将为空。 请检查完整的代码,我发布的解决方案不关心您的 DTO,只需跟踪您正在操作的文档。 问题是如果构造的实体已经分配了 ID 但它在数据库中不存在,我猜你的解决方案将不起作用。如果 ID 存在,我在这里缺少一些检查存储库的例程。 你可以添加逻辑来满足你的业务对吧?就个人而言,我一直使用 Spring Data 来生成 ID。或者分享您的可行解决方案作为额外答案,它会帮助其他人。【参考方案2】:我正在发布另一个解决方案,它使用输入 id 来支持更新操作:
@Component
@RequiredArgsConstructor
public class AuditCallback implements ReactiveBeforeConvertCallback<AuditableEntity>
private final ReactiveMongoTemplate mongoTemplate;
private Mono<?> exists(Object id, Class<?> entityClass)
if (id == null)
return Mono.empty();
return mongoTemplate.findById(id, entityClass);
@Override
public Publisher<AuditableEntity> onBeforeConvert(AuditableEntity entity, String collection)
var securityContext = ReactiveSecurityContextHolder.getContext();
return securityContext
.zipWith(exists(entity.getId(), entity.getClass()))
.map(tuple2 ->
var auditableEntity = (AuditableEntity) tuple2.getT2();
auditableEntity.setLastModifiedBy(tuple2.getT1().getAuthentication().getName());
auditableEntity.setLastModifiedDate(Instant.now());
return auditableEntity;
)
.switchIfEmpty(Mono.zip(securityContext, Mono.just(entity))
.map(tuple2 ->
var auditableEntity = (AuditableEntity) tuple2.getT2();
String principal = tuple2.getT1().getAuthentication().getName();
Instant now = Instant.now();
auditableEntity.setLastModifiedBy(principal);
auditableEntity.setCreatedBy(principal);
auditableEntity.setLastModifiedDate(now);
auditableEntity.setCreatedDate(now);
return auditableEntity;
));
【讨论】:
【参考方案3】:要填充 createdBy 属性,您需要将您的 auditAware bean 与注释 @EnableMongoAuditing 链接
在你的 MongoConfig 类中,定义你的 bean:
@Bean(name = "auditorAware")
public AuditorAware<String> auditor()
....
并在注释中使用它:
@Configuration
@EnableMongoAuditing(auditorAwareRef="auditorAware")
class MongoConfig
....
【讨论】:
目前还没有对反应性使用的审计支持。目前,审计员从ThreadLocal
中撤出,由于不断的线程切换和延迟执行,这不适用于被动使用。
@RichardSinelle 您是否在 reactive 应用程序中尝试过此审核功能?
我开始实现一个原型,灵感来自您提供的代码,谢谢。该 bean 是一个 SimpleReactiveMongoRepository。我让你了解最新情况以上是关于如何使 AuditorAware 与 Spring Data Mongo Reactive 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
带有 spring-security AuditorAware 的 spring-data-jpa 应用程序中的 ***Exception
如何使用 @ManyToMany 审核 @JoinTable