代码之家  ›  专栏  ›  技术社区  ›  Hantsy

如何使用Spring Data Mongo Responsive使AuditorAware工作

  •  5
  • Hantsy  · 技术社区  · 7 年前

    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 document类上。我添加了与试镜相关的注释。

    @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 激活它。

    3 回复  |  直到 4 年前
        1
  •  1
  •   Adam Ostrožlík    4 年前

    我正在发布另一个使用输入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;
                            }));
        }
    }
    
        2
  •  1
  •   Hantsy    4 年前

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

    在官方面前 反应性 如果提供了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 .

        3
  •  -2
  •   Richard Sinelle    7 年前

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

    在MongoConfig类中,定义bean:

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

    并在注释中使用它:

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