如何使 AuditorAware 与 Spring 数据 Mongo 响应式一起工作
How to make AuditorAware work with Spring Data Mongo Reactive
Spring Security 5提供了一个,但是当我想实现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();
}
我已经在我的引导中添加了 @EnableMongoAuduting
Application
class。
在 Mongo 文档上 class。我添加了试听相关的注释。
@CreatedDate
private LocalDateTime createdDate;
@CreatedBy
private Username author;
当我添加一个post时,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 引导 2.4.0-M2/Spring 数据通用 2.4.0-M2/Spring 数据 Mongo 3.1 .0-M2包含一个ReactiveAuditorAware
,检查this new sample,注意:使用@EnableReactiveMongoAuditing
激活它。
要填充 createdBy 属性,您需要 link 您的 auditorAware bean 带有注解 @EnableMongoAuditing
在您的 MongoConfig class 中,定义您的 bean :
@Bean(name = "auditorAware")
public AuditorAware<String> auditor() {
....
}
并在注释中使用它:
@Configuration
@EnableMongoAuditing(auditorAwareRef="auditorAware")
class MongoConfig {
....
}
已弃用:更新方案见原文post
在提供官方 reactive AuditAware 之前,有一种替代方法可以通过 Spring 数据 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 来支持更新操作:
@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;
}));
}
}
Spring Security 5提供了一个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();
}
我已经在我的引导中添加了 @EnableMongoAuduting
Application
class。
在 Mongo 文档上 class。我添加了试听相关的注释。
@CreatedDate
private LocalDateTime createdDate;
@CreatedBy
private Username author;
当我添加一个post时,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 引导 2.4.0-M2/Spring 数据通用 2.4.0-M2/Spring 数据 Mongo 3.1 .0-M2包含一个ReactiveAuditorAware
,检查this new sample,注意:使用@EnableReactiveMongoAuditing
激活它。
要填充 createdBy 属性,您需要 link 您的 auditorAware bean 带有注解 @EnableMongoAuditing
在您的 MongoConfig class 中,定义您的 bean :
@Bean(name = "auditorAware")
public AuditorAware<String> auditor() {
....
}
并在注释中使用它:
@Configuration
@EnableMongoAuditing(auditorAwareRef="auditorAware")
class MongoConfig {
....
}
已弃用:更新方案见原文post
在提供官方 reactive AuditAware 之前,有一种替代方法可以通过 Spring 数据 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 来支持更新操作:
@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;
}));
}
}