如何使AuditorAware与Spring Data Mongo Reactive配合使用

时间:2018-01-01 06:01:24

标签: spring spring-security spring-data-mongodb project-reactor spring-webflux

Spring Security 5提供ReactiveSecurityContextHolder to fetch the SecurityContext from a Reactive context,但是当我想实现AuditorAware并自动获得试听时,但它不起作用。 目前我找不到Reactive AuditorAware变体。

@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

在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。

3 个答案:

答案 0 :(得分:1)

我正在发布另一个解决方案,该解决方案的输入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;
                        }));
    }
}

答案 1 :(得分:0)

已弃用:请参阅原始帖子中的更新解决方案

在提供正式的反应性 AuditAware之前,还有另一种方法可以通过特定于Spring Data Mongo的ReactiveBeforeConvertCallback来实现。

  1. 请勿使用@EnableMongoAuditing
  2. 实施自己的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

答案 2 :(得分:-2)

要填充createdBy属性,您需要将auditorAware bean与注释链接@EnableMongoAuditing

在MongoConfig类中,定义你的bean:

@Bean(name = "auditorAware")
public AuditorAware<String> auditor() {
    ....
}

并在注释中使用它:

@Configuration
@EnableMongoAuditing(auditorAwareRef="auditorAware")
class MongoConfig {
    ....
}