浏览代码

增加DimensionManager

zhou-hao 3 年之前
父节点
当前提交
470c1a0722

+ 44 - 1
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java

@@ -3,14 +3,57 @@ package org.hswebframework.web.authorization;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
+import java.util.Collection;
+
+/**
+ * 维度提供商,用户管理维度信息
+ *
+ * @author zhouhao
+ * @since 4.0
+ */
 public interface DimensionProvider {
 
+    /**
+     * 获取全部支持的维度
+     *
+     * @return 全部支持的维度
+     */
     Flux<? extends DimensionType> getAllType();
 
+    /**
+     * 获取用户获取维度信息
+     *
+     * @param userId 用户ID
+     * @return 维度列表
+     */
     Flux<? extends Dimension> getDimensionByUserId(String userId);
 
+    /**
+     * 根据维度类型和ID获取维度信息
+     *
+     * @param type 类型
+     * @param id   ID
+     * @return 维度信息
+     */
     Mono<? extends Dimension> getDimensionById(DimensionType type, String id);
 
-    Flux<String> getUserIdByDimensionId(String dimensionId);
+    /**
+     * 根据维度类型和Id获取多个维度
+     * @param type 类型
+     * @param idList ID
+     * @return 维度信息
+     */
+    default Flux<? extends Dimension> getDimensionsById(DimensionType type, Collection<String> idList){
+        return Flux
+                .fromIterable(idList)
+                .flatMap(id->this.getDimensionById(type,id));
+    }
 
+    /**
+     * 根据维度ID获取用户ID
+     *
+     * @param dimensionId 维度ID
+     * @return 用户ID
+     */
+    Flux<String> getUserIdByDimensionId(String dimensionId);
 }

+ 25 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionManager.java

@@ -0,0 +1,25 @@
+package org.hswebframework.web.authorization.dimension;
+
+import reactor.core.publisher.Flux;
+
+import java.util.Collection;
+
+/**
+ * 维度管理器
+ *
+ * @author zhouhao
+ * @since 4.0.12
+ */
+public interface DimensionManager {
+
+    /**
+     * 获取用户维度
+     *
+     * @param type   维度类型
+     * @param userId 用户ID
+     * @return 用户维度信息
+     */
+    Flux<DimensionUserDetail> getUserDimension(Collection<String> userId);
+
+
+}

+ 19 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBind.java

@@ -0,0 +1,19 @@
+package org.hswebframework.web.authorization.dimension;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class DimensionUserBind {
+     private String userId;
+
+     private String dimensionType;
+
+     private String dimensionId;
+
+}

+ 11 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserBindProvider.java

@@ -0,0 +1,11 @@
+package org.hswebframework.web.authorization.dimension;
+
+import reactor.core.publisher.Flux;
+
+import java.util.Collection;
+
+public interface DimensionUserBindProvider {
+
+    Flux<DimensionUserBind> getDimensionBindInfo(Collection<String> userIdList);
+
+}

+ 33 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/dimension/DimensionUserDetail.java

@@ -0,0 +1,33 @@
+package org.hswebframework.web.authorization.dimension;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.hswebframework.web.authorization.Dimension;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class DimensionUserDetail {
+    private String userId;
+
+    private List<Dimension> dimensions;
+
+    public DimensionUserDetail merge(DimensionUserDetail detail) {
+        DimensionUserDetail newDetail = new DimensionUserDetail();
+        newDetail.setUserId(userId);
+        newDetail.setDimensions(new ArrayList<>());
+        if (null != dimensions) {
+            newDetail.dimensions.addAll(dimensions);
+        }
+        if (null != detail.getDimensions()) {
+            newDetail.dimensions.addAll(detail.getDimensions());
+        }
+        return newDetail;
+    }
+}

+ 14 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java

@@ -3,6 +3,8 @@ package org.hswebframework.web.authorization.simple;
 import org.hswebframework.web.authorization.*;
 import org.hswebframework.web.authorization.builder.AuthenticationBuilderFactory;
 import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory;
+import org.hswebframework.web.authorization.dimension.DimensionManager;
+import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider;
 import org.hswebframework.web.authorization.simple.builder.DataAccessConfigConverter;
 import org.hswebframework.web.authorization.simple.builder.SimpleAuthenticationBuilderFactory;
 import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
@@ -10,6 +12,7 @@ import org.hswebframework.web.authorization.token.*;
 import org.hswebframework.web.authorization.twofactor.TwoFactorValidatorManager;
 import org.hswebframework.web.authorization.twofactor.defaults.DefaultTwoFactorValidatorManager;
 import org.hswebframework.web.convert.CustomMessageConverter;
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -100,4 +103,15 @@ public class DefaultAuthorizationAutoConfiguration {
             }
         };
     }
+
+    @Bean
+    @ConditionalOnMissingBean(DimensionManager.class)
+    public DimensionManager defaultDimensionManager(ObjectProvider<DimensionUserBindProvider>bindProviders,
+                                                    ObjectProvider<DimensionProvider> providers){
+        DefaultDimensionManager manager =  new DefaultDimensionManager();
+        bindProviders.forEach(manager::addBindProvider);
+        providers.forEach(manager::addProvider);
+
+        return manager;
+    }
 }

+ 90 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultDimensionManager.java

@@ -0,0 +1,90 @@
+package org.hswebframework.web.authorization.simple;
+
+import org.hswebframework.web.authorization.Dimension;
+import org.hswebframework.web.authorization.DimensionProvider;
+import org.hswebframework.web.authorization.dimension.DimensionManager;
+import org.hswebframework.web.authorization.dimension.DimensionUserBind;
+import org.hswebframework.web.authorization.dimension.DimensionUserBindProvider;
+import org.hswebframework.web.authorization.dimension.DimensionUserDetail;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.util.function.Tuple2;
+import reactor.util.function.Tuples;
+
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class DefaultDimensionManager implements DimensionManager {
+
+    private final List<DimensionProvider> dimensionProviders = new CopyOnWriteArrayList<>();
+    private final List<DimensionUserBindProvider> bindProviders = new CopyOnWriteArrayList<>();
+
+    private final Mono<Map<String, DimensionProvider>> providerMapping = Flux
+            .defer(() -> Flux.fromIterable(dimensionProviders))
+            .flatMap(provider -> provider
+                    .getAllType()
+                    .map(type -> Tuples.of(type.getId(), provider)))
+            .collectMap(Tuple2::getT1, Tuple2::getT2);
+
+    public DefaultDimensionManager() {
+
+    }
+
+    public void addProvider(DimensionProvider provider) {
+        dimensionProviders.add(provider);
+    }
+
+    public void addBindProvider(DimensionUserBindProvider bindProvider) {
+        bindProviders.add(bindProvider);
+    }
+
+    private Mono<Map<String, DimensionProvider>> providerMapping() {
+        return providerMapping;
+    }
+
+    @Override
+    public Flux<DimensionUserDetail> getUserDimension(Collection<String> userId) {
+        return this
+                .providerMapping()
+                .flatMapMany(providerMapping -> Flux
+                        .fromIterable(bindProviders)
+                        //获取绑定信息
+                        .flatMap(provider -> provider.getDimensionBindInfo(userId))
+                        .groupBy(DimensionUserBind::getDimensionType)
+                        .flatMap(group -> {
+                            String type = String.valueOf(group.key());
+                            Flux<DimensionUserBind> binds = group.cache();
+                            DimensionProvider provider = providerMapping.get(type);
+                            if (null == provider) {
+                                return Mono.empty();
+                            }
+                            //获取维度信息
+                            return binds
+                                    .map(DimensionUserBind::getDimensionId)
+                                    .collect(Collectors.toSet())
+                                    .flatMapMany(idList -> provider.getDimensionsById(SimpleDimensionType.of(type), idList))
+                                    .collectMap(Dimension::getId, Function.identity())
+                                    .flatMapMany(mapping -> binds
+                                            .groupBy(DimensionUserBind::getUserId)
+                                            .flatMap(userGroup -> Mono
+                                                    .zip(
+                                                            Mono.just(String.valueOf(userGroup.key())),
+                                                            userGroup
+                                                                    .<Dimension>handle((bind, sink) -> {
+                                                                        Dimension dimension = mapping.get(bind.getDimensionId());
+                                                                        if (dimension != null) {
+                                                                            sink.next(dimension);
+                                                                        }
+                                                                    })
+                                                                    .collectList(),
+                                                            DimensionUserDetail::of
+                                                    ))
+                                    );
+                        })
+                        )
+                .groupBy(DimensionUserDetail::getUserId)
+                .flatMap(group->group.reduce(DimensionUserDetail::merge));
+    }
+}

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

@@ -1,6 +1,10 @@
 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;
@@ -8,6 +12,8 @@ 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.service.GenericReactiveTreeSupportCrudService;
 import org.hswebframework.web.crud.service.ReactiveCrudService;
@@ -24,14 +30,14 @@ import org.springframework.context.ApplicationEventPublisher;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
-import java.util.List;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 public class DefaultDimensionService
         extends GenericReactiveTreeSupportCrudService<DimensionEntity, String>
         implements
-        DimensionProvider {
+        DimensionProvider, DimensionUserBindProvider {
 
     @Autowired
     private ReactiveRepository<DimensionUserEntity, String> dimensionUserRepository;
@@ -64,39 +70,56 @@ public class DefaultDimensionService
 
     @Override
     public Mono<DynamicDimension> getDimensionById(DimensionType type, String id) {
-
         return createQuery()
-                .where(DimensionEntity::getId,id)
+                .where(DimensionEntity::getId, id)
                 .fetch()
                 .singleOrEmpty()
-                .map(entity-> DynamicDimension.of(entity, type));
+                .map(entity -> DynamicDimension.of(entity, type));
+    }
+
+    @Override
+    public Flux<? extends Dimension> getDimensionsById(DimensionType type, Collection<String> idList) {
+        return this.createQuery()
+                   .where(DimensionEntity::getTypeId, type.getId())
+                   .in(DimensionEntity::getId, idList)
+                   .fetch()
+                   .map(entity -> DynamicDimension.of(entity, type));
     }
 
     @Override
     public Flux<DynamicDimension> getDimensionByUserId(String userId) {
         return getAllType()
                 .collect(Collectors.toMap(DimensionType::getId, Function.identity()))
-                .flatMapMany(typeGrouping ->
-                        dimensionUserRepository
-                                .createQuery()
-                                .where(DimensionUserEntity::getUserId, userId)
-                                .fetch()
-                                .collectList()
-                                .filter(CollectionUtils::isNotEmpty)
-                                .flatMapMany(list -> {
-                                    //查询所有的维度
-                                    return this.queryIncludeChildren(list.stream()
-                                            .map(DimensionUserEntity::getDimensionId)
-                                            .collect(Collectors.toSet()))
-                                            .filter(dimension -> typeGrouping.containsKey(dimension.getTypeId()))
-                                            .map(dimension ->
-                                                    DynamicDimension.of(dimension, typeGrouping.get(dimension.getTypeId()))
-                                            );
-
-                                })
+                .flatMapMany(typeGrouping -> dimensionUserRepository
+                        .createQuery()
+                        .where(DimensionUserEntity::getUserId, userId)
+                        .fetch()
+                        .collectList()
+                        .filter(CollectionUtils::isNotEmpty)
+                        .flatMapMany(list -> {
+                            //查询所有的维度
+                            return this
+                                    .queryIncludeChildren(list.stream()
+                                                              .map(DimensionUserEntity::getDimensionId)
+                                                              .collect(Collectors.toSet()))
+                                    .filter(dimension -> typeGrouping.containsKey(dimension.getTypeId()))
+                                    .map(dimension ->
+                                                 DynamicDimension.of(dimension, typeGrouping.get(dimension.getTypeId()))
+                                    );
+
+                        })
                 );
     }
 
+    @Override
+    public Flux<DimensionUserBind> getDimensionBindInfo(Collection<String> userIdList) {
+        return dimensionUserRepository
+                .createQuery()
+                .in(DimensionUserEntity::getUserId, userIdList)
+                .fetch()
+                .map(entity -> DimensionUserBind.of(entity.getUserId(), entity.getDimensionTypeId(), entity.getDimensionId()));
+    }
+
     @Override
     @SuppressWarnings("all")
     public Flux<String> getUserIdByDimensionId(String dimensionId) {
@@ -111,49 +134,50 @@ public class DefaultDimensionService
     @Override
     public Mono<SaveResult> save(Publisher<DimensionEntity> entityPublisher) {
         return super.save(entityPublisher)
-                .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()));
+                    .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()));
+                    .doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all()));
     }
 
     @Override
     public ReactiveUpdate<DimensionEntity> createUpdate() {
         return super.createUpdate()
-                .onExecute((update, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())));
+                    .onExecute((update, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())));
     }
 
     @Override
     public ReactiveDelete createDelete() {
         return super.createDelete()
-                .onExecute((delete, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())));
+                    .onExecute((delete, result) -> result.doOnSuccess((r) -> eventPublisher.publishEvent(ClearUserAuthorizationCacheEvent.all())));
     }
 
     @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()));
+                   .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()));
     }
 
 }