Browse Source

优化维度权限绑定解绑逻辑

zhouhao 3 năm trước cách đây
mục cha
commit
bc5e68a09b

+ 1 - 0
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java

@@ -67,6 +67,7 @@ public class AuthorizationSettingEntity implements Entity {
     @Comment("状态")
     @NotNull(message = "状态不能为空",groups = CreateGroup.class)
     @Schema(description = "状态,0禁用,1启用")
+    @DefaultValue("1")
     private Byte state;
 
     @Column

+ 2 - 0
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionEntity.java

@@ -7,6 +7,7 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType;
 import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
 import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec;
 import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity;
+import org.hswebframework.web.crud.annotation.EnableEntityEvent;
 import org.hswebframework.web.validator.CreateGroup;
 
 import javax.persistence.Column;
@@ -24,6 +25,7 @@ import java.util.Map;
 @Table(name = "s_dimension", indexes = {
         @Index(name = "idx_dims_path", columnList = "path")
 })
+@EnableEntityEvent
 public class DimensionEntity extends GenericTreeSortSupportEntity<String> {
 
     @Override

+ 4 - 1
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DimensionUserEntity.java

@@ -7,6 +7,7 @@ import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType;
 import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
 import org.hswebframework.ezorm.rdb.mapping.annotation.EnumCodec;
 import org.hswebframework.web.api.crud.entity.GenericEntity;
+import org.hswebframework.web.crud.annotation.EnableEntityEvent;
 import org.hswebframework.web.dict.EnumDict;
 import org.hswebframework.web.system.authorization.api.enums.DimensionUserFeature;
 import org.springframework.util.DigestUtils;
@@ -26,6 +27,7 @@ import java.sql.JDBCType;
         @Index(name = "idx_dimsu_user_id", columnList = "user_id"),
 
 })
+@EnableEntityEvent
 public class DimensionUserEntity extends GenericEntity<String> {
 
     @Comment("维度类型ID")
@@ -40,13 +42,14 @@ public class DimensionUserEntity extends GenericEntity<String> {
 
     @Comment("维度名称")
     @Column(name = "dimension_name", nullable = false)
-    @NotBlank(message = "[dimensionName]不能为空")
+    @NotBlank
     @Schema(description = "维度名称")
     private String dimensionName;
 
     @Comment("用户ID")
     @Column(name = "user_id", nullable = false, length = 64)
     @Schema(description = "用户ID")
+    @NotBlank
     private String userId;
 
     @Comment("用户名")

+ 12 - 0
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultAuthorizationSettingService.java

@@ -43,6 +43,18 @@ public class DefaultAuthorizationSettingService extends GenericReactiveCrudServi
         return entity;
     }
 
+    @Override
+    public Mono<SaveResult> save(AuthorizationSettingEntity data) {
+        generateId(data);
+        return super.save(data);
+    }
+
+    @Override
+    public Mono<SaveResult> save(Collection<AuthorizationSettingEntity> collection) {
+        collection.forEach(this::generateId);
+        return super.save(collection);
+    }
+
     @Override
     public Mono<SaveResult> save(Publisher<AuthorizationSettingEntity> entityPublisher) {
         return Flux.from(entityPublisher)

+ 19 - 58
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java

@@ -1,36 +1,30 @@
 package org.hswebframework.web.system.authorization.defaults.service;
 
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections4.BidiMap;
-import org.apache.commons.collections4.MultiValuedMap;
-import org.apache.commons.collections4.bidimap.DualHashBidiMap;
-import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
-import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete;
 import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
-import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate;
-import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
 import org.hswebframework.web.authorization.Dimension;
 import org.hswebframework.web.authorization.DimensionProvider;
 import org.hswebframework.web.authorization.DimensionType;
 import org.hswebframework.web.authorization.dimension.DimensionUserBind;
 import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider;
-import org.hswebframework.web.crud.service.GenericReactiveCrudService;
+import org.hswebframework.web.crud.events.EntityDeletedEvent;
+import org.hswebframework.web.crud.events.EntityModifyEvent;
+import org.hswebframework.web.crud.events.EntitySavedEvent;
 import org.hswebframework.web.crud.service.GenericReactiveTreeSupportCrudService;
-import org.hswebframework.web.crud.service.ReactiveCrudService;
-import org.hswebframework.web.crud.service.ReactiveTreeSortEntityService;
 import org.hswebframework.web.id.IDGenerator;
-import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity;
 import org.hswebframework.web.system.authorization.api.entity.DimensionEntity;
 import org.hswebframework.web.system.authorization.api.entity.DimensionTypeEntity;
 import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity;
 import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent;
-import org.reactivestreams.Publisher;
+import org.hswebframework.web.system.authorization.api.event.DimensionDeletedEvent;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -45,9 +39,6 @@ public class DefaultDimensionService
     @Autowired
     private ReactiveRepository<DimensionTypeEntity, String> dimensionTypeRepository;
 
-    @Autowired
-    private ReactiveRepository<AuthorizationSettingEntity, String> settingRepository;
-
     @Autowired
     private ApplicationEventPublisher eventPublisher;
 
@@ -131,53 +122,23 @@ public class DefaultDimensionService
                 .map(DimensionUserEntity::getUserId);
     }
 
-    @Override
-    public Mono<SaveResult> save(Publisher<DimensionEntity> entityPublisher) {
-        return super.save(entityPublisher)
-                    .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()));
-    }
-
-    @Override
-    public Mono<Integer> updateById(String id, Mono<DimensionEntity> entityPublisher) {
-        return super.updateById(id, entityPublisher)
-                    .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()));
+    @EventListener
+    public void handleDimensionChanged(EntitySavedEvent<DimensionEntity> event) {
+        eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all());
     }
 
-    @Override
-    public ReactiveUpdate<DimensionEntity> createUpdate() {
-        return super.createUpdate()
-                    .onExecute((update, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())));
+    @EventListener
+    public void handleDimensionChanged(EntityModifyEvent<DimensionEntity> event) {
+        eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all());
     }
 
-    @Override
-    public ReactiveDelete createDelete() {
-        return super.createDelete()
-                    .onExecute((delete, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())));
-    }
+    @EventListener
+    public void dispatchDimensionDeleteEvent(EntityDeletedEvent<DimensionEntity> event) {
 
-    @Override
-    public Mono<Integer> deleteById(Publisher<String> idPublisher) {
-
-        return Flux.from(idPublisher)
-                   .collectList()
-                   .flatMap(list -> super.queryIncludeChildren(list)
-                                         .flatMap(dimension -> dimensionUserRepository.createDelete() //删除维度用户关联
-                                                                                      .where()
-                                                                                      .is(DimensionUserEntity::getDimensionId, dimension.getId())
-                                                                                      .execute()
-                                                                                      .then(getRepository().deleteById(Mono.just(dimension.getId())))
-                                                                                      .thenReturn(dimension)
-                                         )
-                                         .groupBy(DimensionEntity::getTypeId, DimensionEntity::getId)//按维度类型分组
-                                         .flatMap(grouping -> grouping.collectList()
-                                                                      .flatMap(dimensionId -> settingRepository //删除权限设置
-                                                                                                                .createDelete()
-                                                                                                                .where(AuthorizationSettingEntity::getDimensionType, grouping.key())
-                                                                                                                .in(AuthorizationSettingEntity::getDimensionTarget, dimensionId)
-                                                                                                                .execute()))
-                                         .collect(Collectors.summarizingInt(Integer::intValue))
-                                         .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()))
-                                         .thenReturn(list.size()));
+        event.async(
+                Flux.fromIterable(event.getEntity())
+                    .flatMap(e -> new DimensionDeletedEvent(e.getTypeId(), e.getId()).publish(eventPublisher))
+        );
     }
 
 }

+ 68 - 57
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java

@@ -5,9 +5,14 @@ import org.hswebframework.ezorm.rdb.exception.DuplicateKeyException;
 import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete;
 import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate;
 import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
+import org.hswebframework.web.crud.events.EntityCreatedEvent;
+import org.hswebframework.web.crud.events.EntityDeletedEvent;
+import org.hswebframework.web.crud.events.EntityModifyEvent;
+import org.hswebframework.web.crud.events.EntitySavedEvent;
 import org.hswebframework.web.crud.service.GenericReactiveCrudService;
 import org.hswebframework.web.event.AsyncEvent;
 import org.hswebframework.web.exception.BusinessException;
+import org.hswebframework.web.system.authorization.api.entity.DimensionEntity;
 import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity;
 import org.hswebframework.web.system.authorization.api.event.ClearUserAuthorizationCacheEvent;
 import org.hswebframework.web.system.authorization.api.event.DimensionBindEvent;
@@ -22,8 +27,13 @@ import reactor.core.publisher.Mono;
 import reactor.function.Function3;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.*;
 
 @Slf4j
 public class DefaultDimensionUserService extends GenericReactiveCrudService<DimensionUserEntity, String> {
@@ -31,6 +41,7 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService<Dime
     @Autowired
     private ApplicationEventPublisher eventPublisher;
 
+    //处理用户被删除时,同步删除维度绑定信息
     @EventListener
     public void handleUserDeleteEntity(UserDeletedEvent event) {
         event.async(this.createDelete()
@@ -40,36 +51,62 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService<Dime
         );
     }
 
-    @Override
-    public Mono<SaveResult> save(Publisher<DimensionUserEntity> entityPublisher) {
-        return this
-                .publishEvent(entityPublisher, DimensionBindEvent::new)
-                .as(super::save);
+    //转发保存维度信息到DimensionBindEvent事件,并清空权限缓存
+    @EventListener
+    public void dispatchDimensionBind(EntitySavedEvent<DimensionUserEntity> event) {
+        event.async(
+                this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new)
+                    .then(
+                            this.clearUserCache(event.getEntity())
+                    )
+        );
     }
 
-    @Override
-    public Mono<Integer> updateById(String id, Mono<DimensionUserEntity> entityPublisher) {
-        return entityPublisher
-                .doOnNext(entity -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.of(entity.getUserId())))
-                .as(e -> super.updateById(id, e));
+    //新增绑定时转发DimensionBindEvent并清空用户权限信息
+    @EventListener
+    public void dispatchDimensionBind(EntityCreatedEvent<DimensionUserEntity> event) {
+        event.async(
+                this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new)
+                    .then(
+                            this.clearUserCache(event.getEntity())
+                    )
+        );
     }
 
-    @Override
-    public Mono<Integer> insert(Publisher<DimensionUserEntity> entityPublisher) {
-        return this
-                .publishEvent(entityPublisher, DimensionBindEvent::new)
-                .as(super::insert)
-                .onErrorMap(DuplicateKeyException.class, (err) -> new BusinessException("error.duplicate_key"));
+    //删除绑定时转发DimensionUnbindEvent并清空用户权限信息
+    @EventListener
+    public void dispatchDimensionUnbind(EntityDeletedEvent<DimensionUserEntity> event) {
+        event.async(
+                this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionUnbindEvent::new)
+                    .then(
+                            this.clearUserCache(event.getEntity())
+                    )
+        );
     }
 
-    @Override
-    public Mono<Integer> insertBatch(Publisher<? extends Collection<DimensionUserEntity>> entityPublisher) {
+    //修改绑定信息时清空权限
+    @EventListener
+    public void handleModifyEvent(EntityModifyEvent<DimensionUserEntity> event) {
+        event.async(
+                this.clearUserCache(event.getAfter())
+        );
+    }
 
-        Flux<? extends Collection<DimensionUserEntity>> cache = Flux.from(entityPublisher).cache();
+    //维度被删除时同时删除绑定信息
+    @EventListener
+    public void handleDimensionDeletedEntity(EntityDeletedEvent<DimensionEntity> event) {
+        event.async(
+                Flux.fromIterable(event.getEntity())
+                    .collect(groupingBy(DimensionEntity::getTypeId,
+                                        mapping(DimensionEntity::getId, toSet())))
+                    .flatMapIterable(Map::entrySet)
+                    .flatMap(entry -> this
+                            .createDelete()
+                            .where(DimensionUserEntity::getDimensionTypeId, entry.getKey())
+                            .in(DimensionUserEntity::getDimensionId, entry.getValue())
+                            .execute())
+        );
 
-        return this
-                .publishEvent(cache.flatMapIterable(Function.identity()), DimensionBindEvent::new)
-                .then(super.insertBatch(cache));
     }
 
     private Flux<DimensionUserEntity> publishEvent(Publisher<DimensionUserEntity> stream,
@@ -83,7 +120,6 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService<Dime
                             .groupBy(DimensionUserEntity::getDimensionId)
                             .flatMap(dimensionIdGroup -> {
                                 String dimensionId = dimensionIdGroup.key();
-
                                 return dimensionIdGroup
                                         .map(DimensionUserEntity::getUserId)
                                         .collectList()
@@ -96,39 +132,14 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService<Dime
                 .thenMany(cache);
     }
 
-    @Override
-    @SuppressWarnings("all")
-    public ReactiveUpdate<DimensionUserEntity> createUpdate() {
-        return super
-                .createUpdate()
-                .onExecute((update, r) -> r
-                        .flatMap(result -> this
-                                .createQuery()
-                                .select(DimensionUserEntity::getUserId)
-                                .setParam(update.toQueryParam())
-                                .fetch()
-                                .map(DimensionUserEntity::getUserId)
-                                .distinct()
-                                .collectList()
-                                .map(ClearUserAuthorizationCacheEvent::of)
-                                .doOnNext(eventPublisher::publishEvent)
-                                .thenReturn(result)
-                        )
-                );
+    private Mono<Void> clearUserCache(List<DimensionUserEntity> entities) {
+        return Flux.fromIterable(entities)
+                   .map(DimensionUserEntity::getUserId)
+                   .distinct()
+                   .collectList()
+                   .map(ClearUserAuthorizationCacheEvent::of)
+                   .doOnNext(eventPublisher::publishEvent)
+                   .then();
     }
 
-    @Override
-    @SuppressWarnings("all")
-    public ReactiveDelete createDelete() {
-        return super
-                .createDelete()
-                .onExecute((delete, r) -> this
-                        .publishEvent(this.createQuery()
-                                          .select(DimensionUserEntity::getUserId)
-                                          .setParam(delete.toQueryParam())
-                                          .fetch(),
-                                      DimensionUnbindEvent::new
-                        ).then(r)
-                );
-    }
-}
+}

+ 208 - 0
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserServiceTest.java

@@ -0,0 +1,208 @@
+package org.hswebframework.web.system.authorization.defaults.service;
+
+import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
+import org.hswebframework.web.authorization.AuthenticationManager;
+import org.hswebframework.web.authorization.ReactiveAuthenticationManager;
+import org.hswebframework.web.system.authorization.api.entity.*;
+import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService;
+import org.hswebframework.web.system.authorization.defaults.service.reactive.ReactiveTestApplication;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = ReactiveTestApplication.class)
+public class DefaultDimensionUserServiceTest {
+
+    @Autowired
+    private ReactiveUserService userService;
+
+    @Autowired
+    private ReactiveRepository<DimensionTypeEntity, String> typeRepository;
+
+    @Autowired
+    private DefaultDimensionService dimensionService;
+
+    @Autowired
+    private DefaultDimensionUserService dimensionUserService;
+
+    @Autowired
+    private DefaultAuthorizationSettingService settingService;
+
+    @Autowired
+    private ReactiveAuthenticationManager authenticationManager;
+
+    @Test
+    public void testDeleteBind() {
+        String dimensionType = "role";
+        String dimensionId = "testDeleteBind";
+        String userId = initData(dimensionType, dimensionId);
+
+        //删除绑定关系
+        dimensionUserService
+                .createDelete()
+                .where(DimensionUserEntity::getUserId, userId)
+                .execute()
+                .then()
+                .as(StepVerifier::create)
+                .expectComplete()
+                .verify();
+
+        //校验权限
+        authenticationManager
+                .getByUserId(userId)
+                .map(auth -> !auth.hasDimension(dimensionType, dimensionId))
+                .as(StepVerifier::create)
+                .expectNext(true)
+                .verifyComplete();
+
+        //权限设置并没有被删除
+        settingService
+                .createQuery()
+                .where(AuthorizationSettingEntity::getDimensionType, dimensionType)
+                .and(AuthorizationSettingEntity::getDimensionTarget, dimensionId)
+                .count()
+                .as(StepVerifier::create)
+                .expectNext(1)
+                .verifyComplete();
+
+    }
+
+    @Test
+    public void testDeleteDimension() {
+        String dimensionType = "role";
+        String dimensionId = "testDeleteDimension";
+        String userId = initData(dimensionType, dimensionId);
+
+        //删除维度
+        dimensionService
+                .deleteById(dimensionId)
+                .then()
+                .as(StepVerifier::create)
+                .expectComplete()
+                .verify();
+
+        //判断没有维度
+        authenticationManager
+                .getByUserId(userId)
+                .map(auth -> !auth.hasDimension(dimensionType, dimensionId))
+                .as(StepVerifier::create)
+                .expectNext(true)
+                .verifyComplete();
+
+        //权限设置也被删除
+        settingService
+                .createQuery()
+                .where(AuthorizationSettingEntity::getDimensionType, dimensionType)
+                .and(AuthorizationSettingEntity::getDimensionTarget, dimensionId)
+                .count()
+                .as(StepVerifier::create)
+                .expectNext(0)
+                .verifyComplete();
+
+
+    }
+
+    @Test
+    public void testDeleteUser() {
+        String dimensionType = "role";
+        String dimensionId = "test";
+
+        String userId = initData(dimensionType, dimensionId);
+
+        userService.deleteUser(userId)
+                   .as(StepVerifier::create)
+                   .expectNext(true)
+                   .verifyComplete();
+
+        authenticationManager
+                .getByUserId(userId)
+                .as(StepVerifier::create)
+                .expectNextCount(0)
+                .verifyComplete();
+
+
+        dimensionUserService
+                .createQuery()
+                .where(DimensionUserEntity::getUserId, userId)
+                .count()
+                .as(StepVerifier::create)
+                .expectNext(0)
+                .verifyComplete();
+
+    }
+
+
+    private String initData(String dimensionType, String dimensionId) {
+        UserEntity userEntity = userService.newUserInstance().blockOptional().orElseThrow(NullPointerException::new);
+        userEntity.setName("test");
+        userEntity.setUsername("test_" + dimensionId);
+        userEntity.setPassword("admin");
+        userService.saveUser(Mono.just(userEntity))
+                   .as(StepVerifier::create)
+                   .expectNext(true)
+                   .verifyComplete();
+
+        DimensionTypeEntity type = new DimensionTypeEntity();
+        type.setId(dimensionType);
+        type.setName(dimensionType);
+        typeRepository.save(type)
+                      .then()
+                      .as(StepVerifier::create)
+                      .expectComplete()
+                      .verify();
+
+        DimensionEntity dimension = new DimensionEntity();
+        dimension.setId(dimensionId);
+        dimension.setTypeId(dimensionType);
+        dimension.setName(dimensionId);
+
+        dimensionService
+                .save(dimension)
+                .then()
+                .as(StepVerifier::create)
+                .expectComplete()
+                .verify();
+
+        DimensionUserEntity bind = new DimensionUserEntity();
+        bind.setDimensionId(dimension.getId());
+        bind.setDimensionTypeId(dimension.getTypeId());
+        bind.setDimensionName(dimension.getName());
+        bind.setUserId(userEntity.getId());
+        bind.setUserName(userEntity.getName());
+        dimensionUserService
+                .save(bind)
+                .then()
+                .as(StepVerifier::create)
+                .expectComplete()
+                .verify();
+
+        AuthorizationSettingEntity setting = new AuthorizationSettingEntity();
+        setting.setDimensionType(dimension.getTypeId());
+        setting.setDimensionTarget(dimension.getId());
+        setting.setPermission("test");
+
+        settingService
+                .insert(setting)
+                .then()
+                .as(StepVerifier::create)
+                .expectComplete()
+                .verify();
+
+        authenticationManager
+                .getByUserId(userEntity.getId())
+                .map(auth -> auth.hasDimension(dimensionType, dimensionId))
+                .as(StepVerifier::create)
+                .expectNext(true)
+                .verifyComplete();
+
+        return userEntity.getId();
+    }
+
+}