浏览代码

增加维度数据权限

zhou-hao 5 年之前
父节点
当前提交
4bcef2f250
共有 31 个文件被更改,包括 922 次插入63 次删除
  1. 2 2
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java
  2. 6 5
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DataAccessConfig.java
  3. 4 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DataAccessConfiguration.java
  4. 67 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DimensionHelper.java
  5. 5 1
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/DataAccessType.java
  6. 31 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/DimensionDataAccess.java
  7. 2 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/ResourceAction.java
  8. 3 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/DataAccessTypeDefinition.java
  9. 2 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourceDefinition.java
  10. 4 5
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java
  11. 30 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DimensionDataAccessConfig.java
  12. 1 1
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/builder/DataAccessConfigConvert.java
  13. 2 2
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/builder/SimpleDataAccessConfigBuilder.java
  14. 9 6
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/builder/SimpleDataAccessConfigBuilderFactory.java
  15. 92 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/RedisUserTokenManager.java
  16. 19 0
      hsweb-authorization/hsweb-authorization-basic/pom.xml
  17. 1 0
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java
  18. 3 0
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java
  19. 60 0
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/DataAccessHandlerContext.java
  20. 2 1
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/DefaultDataAccessController.java
  21. 382 0
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/DimensionDataAccessHandler.java
  22. 1 0
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/FieldFilterDataAccessHandler.java
  23. 80 25
      hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingControllerTest.java
  24. 2 0
      hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestApplication.java
  25. 33 4
      hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestController.java
  26. 22 0
      hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestDataAccess.java
  27. 20 0
      hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestEntity.java
  28. 6 1
      hsweb-authorization/hsweb-authorization-basic/src/test/resources/application.yml
  29. 3 0
      hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java
  30. 17 5
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java
  31. 11 5
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DynamicDimension.java

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

@@ -4,9 +4,9 @@ import reactor.core.publisher.Flux;
 
 public interface DimensionProvider {
 
-    Flux<DimensionType> getAllType();
+    Flux<? extends DimensionType> getAllType();
 
-    Flux<Dimension> getDimensionByUserId(String userId);
+    Flux<? extends Dimension> getDimensionByUserId(String userId);
 
     Flux<String> getUserIdByDimensionId(String dimensionId);
 

+ 6 - 5
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DataAccessConfig.java

@@ -62,19 +62,20 @@ public interface DataAccessConfig extends Serializable {
          * @see OwnCreatedDataAccessConfig#getType()
          */
         String OWN_CREATED = "OWN_CREATED";
+
         /**
-         * 字段值范围
+         * 禁止操作字段
          *
-         * @see FieldScopeDataAccessConfig#getType()
+         * @see FieldFilterDataAccessConfig#getType()
          */
-        String FIELD_SCOPE = "FIELD_SCOPE";
+        String DENY_FIELDS = "DENY_FIELDS";
 
         /**
          * 禁止操作字段
          *
-         * @see FieldFilterDataAccessConfig#getType()
+         * @see org.hswebframework.web.authorization.simple.DimensionDataAccessConfig#getType()
          */
-        String DENY_FIELDS = "DENY_FIELDS";
+        String DIMENSION_SCOPE = "DIMENSION_SCOPE";
 
 
     }

+ 4 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DataAccessConfiguration.java

@@ -0,0 +1,4 @@
+package org.hswebframework.web.authorization.access;
+
+public interface DataAccessConfiguration {
+}

+ 67 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DimensionHelper.java

@@ -0,0 +1,67 @@
+package org.hswebframework.web.authorization.access;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+import org.hswebframework.web.authorization.Authentication;
+import org.hswebframework.web.authorization.Dimension;
+import org.hswebframework.web.authorization.DimensionType;
+import org.hswebframework.web.authorization.Permission;
+import org.hswebframework.web.authorization.simple.DimensionDataAccessConfig;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public abstract class DimensionHelper {
+
+
+    public static Set<Object> getDimensionDataAccessScope(Authentication atz,
+                                                          Permission permission,
+                                                          String action,
+                                                          String dimensionType) {
+        return permission
+                .getDataAccesses(action)
+                .stream()
+                .filter(DimensionDataAccessConfig.class::isInstance)
+                .map(DimensionDataAccessConfig.class::cast)
+                .filter(conf -> dimensionType.equals(conf.getScopeType()))
+                .flatMap(conf -> {
+                    if (CollectionUtils.isEmpty(conf.getScope())) {
+                        return atz.getDimensions(dimensionType)
+                                .stream()
+                                .map(Dimension::getId);
+                    }
+                    return conf.getScope().stream();
+                }).collect(Collectors.toSet());
+    }
+
+    public static Set<Object> getDimensionDataAccessScope(Authentication atz,
+                                                          Permission permission,
+                                                          String action,
+                                                          DimensionType dimensionType) {
+        return getDimensionDataAccessScope(atz, permission, action, dimensionType.getId());
+    }
+
+
+    public static Set<Object> getDimensionDataAccessScope(Authentication atz,
+                                                          String permission,
+                                                          String action,
+                                                          String dimensionType) {
+        return atz
+                .getPermission(permission)
+                .map(per -> getDimensionDataAccessScope(atz, per, action, dimensionType)).orElseGet(Collections::emptySet);
+    }
+
+    public static Set<Object> getDimensionDataAccessScope(Authentication atz,
+                                                          String permission,
+                                                          String action,
+                                                          DimensionType dimensionType) {
+        return atz
+                .getPermission(permission)
+                .map(per -> getDimensionDataAccessScope(atz, per, action, dimensionType))
+                .orElseGet(Collections::emptySet);
+    }
+
+}

+ 5 - 1
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/DataAccessType.java

@@ -1,5 +1,6 @@
 package org.hswebframework.web.authorization.annotation;
 
+import org.hswebframework.web.authorization.access.DataAccessConfiguration;
 import org.hswebframework.web.authorization.access.DataAccessController;
 
 import java.lang.annotation.*;
@@ -19,5 +20,8 @@ public @interface DataAccessType {
     /**
      * @see DataAccessController
      */
-    Class<? extends DataAccessController> controller() default  DataAccessController.class;
+    Class<? extends DataAccessController> controller() default DataAccessController.class;
+
+    Class<? extends DataAccessConfiguration> configuration() default DataAccessConfiguration.class;
+
 }

+ 31 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/DimensionDataAccess.java

@@ -0,0 +1,31 @@
+package org.hswebframework.web.authorization.annotation;
+
+import org.hswebframework.web.authorization.define.Phased;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+@DataAccessType(id = "dimension", name = "维度数据权限")
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
+@Authorize
+public @interface DimensionDataAccess {
+
+    Mapping[] mapping() default {};
+
+    @AliasFor(annotation = Authorize.class)
+    Phased phased() default  Phased.before;
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Documented
+    @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
+    @interface Mapping {
+        String dimensionType();
+
+        String property();
+
+        int idParamIndex() default -1;
+    }
+
+}

+ 2 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/ResourceAction.java

@@ -1,5 +1,7 @@
 package org.hswebframework.web.authorization.annotation;
 
+import org.hswebframework.web.authorization.define.Phased;
+
 import java.lang.annotation.*;
 
 /**

+ 3 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/DataAccessTypeDefinition.java

@@ -5,6 +5,7 @@ import lombok.Getter;
 import lombok.Setter;
 import org.hswebframework.web.authorization.access.DataAccessController;
 import org.hswebframework.web.authorization.access.DataAccessType;
+import org.hswebframework.web.authorization.access.DataAccessConfiguration;
 import org.hswebframework.web.bean.FastBeanCopier;
 
 @Getter
@@ -19,6 +20,8 @@ public class DataAccessTypeDefinition implements DataAccessType {
 
     private Class<? extends DataAccessController> controller;
 
+    private Class<? extends DataAccessConfiguration> configuration;
+
     public DataAccessTypeDefinition copy(){
         return FastBeanCopier.copy(this,DataAccessTypeDefinition::new);
     }

+ 2 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourceDefinition.java

@@ -33,6 +33,8 @@ public class ResourceDefinition {
 
     private Logical logical = Logical.DEFAULT;
 
+    private Phased phased = Phased.before;
+
     public static ResourceDefinition of(String id, String name) {
         ResourceDefinition definition = new ResourceDefinition();
         definition.setId(id);

+ 4 - 5
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java

@@ -3,7 +3,7 @@ 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.simple.builder.DataAccessConfigConvert;
+import org.hswebframework.web.authorization.simple.builder.DataAccessConfigConverter;
 import org.hswebframework.web.authorization.simple.builder.SimpleAuthenticationBuilderFactory;
 import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory;
 import org.hswebframework.web.authorization.token.DefaultUserTokenManager;
@@ -18,7 +18,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Conditional;
 import org.springframework.context.annotation.Configuration;
 
 import java.util.List;
@@ -30,7 +29,7 @@ import java.util.List;
 public class DefaultAuthorizationAutoConfiguration {
 
     @Autowired(required = false)
-    private List<DataAccessConfigConvert> dataAccessConfigConverts;
+    private List<DataAccessConfigConverter> dataAccessConfigConverters;
 
     @Bean
     @ConditionalOnMissingBean(UserTokenManager.class)
@@ -69,8 +68,8 @@ public class DefaultAuthorizationAutoConfiguration {
     @ConfigurationProperties(prefix = "hsweb.authorization.data-access", ignoreInvalidFields = true)
     public SimpleDataAccessConfigBuilderFactory dataAccessConfigBuilderFactory() {
         SimpleDataAccessConfigBuilderFactory factory = new SimpleDataAccessConfigBuilderFactory();
-        if (null != dataAccessConfigConverts) {
-            dataAccessConfigConverts.forEach(factory::addConvert);
+        if (null != dataAccessConfigConverters) {
+            dataAccessConfigConverters.forEach(factory::addConvert);
         }
         return factory;
     }

+ 30 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DimensionDataAccessConfig.java

@@ -0,0 +1,30 @@
+package org.hswebframework.web.authorization.simple;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.authorization.DimensionType;
+import org.hswebframework.web.authorization.access.DataAccessType;
+import org.hswebframework.web.authorization.access.DefaultDataAccessType;
+import org.hswebframework.web.authorization.access.ScopeDataAccessConfig;
+import org.hswebframework.web.authorization.simple.AbstractDataAccessConfig;
+
+import java.util.Set;
+
+@Getter
+@Setter
+public class DimensionDataAccessConfig extends AbstractDataAccessConfig implements ScopeDataAccessConfig {
+
+    private Set<Object> scope;
+
+    private boolean children;
+
+    /**
+     * @see DimensionType#getId()
+     */
+    private String scopeType;
+
+    @Override
+    public DefaultDataAccessType getType() {
+        return DefaultDataAccessType.DIMENSION_SCOPE;
+    }
+}

+ 1 - 1
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/builder/DataAccessConfigConvert.java

@@ -5,7 +5,7 @@ import org.hswebframework.web.authorization.access.DataAccessConfig;
 /**
  * @author zhouhao
  */
-public interface DataAccessConfigConvert {
+public interface DataAccessConfigConverter {
 
     boolean isSupport(String type, String action, String config);
 

+ 2 - 2
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/builder/SimpleDataAccessConfigBuilder.java

@@ -15,12 +15,12 @@ import java.util.Objects;
  */
 public class SimpleDataAccessConfigBuilder implements DataAccessConfigBuilder {
 
-    private List<DataAccessConfigConvert> converts;
+    private List<DataAccessConfigConverter> converts;
 
     private Map<String, Object> config = new HashMap<>();
 
 
-    public SimpleDataAccessConfigBuilder(List<DataAccessConfigConvert> converts) {
+    public SimpleDataAccessConfigBuilder(List<DataAccessConfigConverter> converts) {
         Objects.requireNonNull(converts);
         this.converts = converts;
     }

+ 9 - 6
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/builder/SimpleDataAccessConfigBuilderFactory.java

@@ -23,12 +23,11 @@ public class SimpleDataAccessConfigBuilderFactory implements DataAccessConfigBui
 
     private List<String> defaultSupportConvert = Arrays.asList(
             OWN_CREATED,
-            FIELD_SCOPE,
             DENY_FIELDS);
 
-    private List<DataAccessConfigConvert> converts = new LinkedList<>();
+    private List<DataAccessConfigConverter> converts = new LinkedList<>();
 
-    public SimpleDataAccessConfigBuilderFactory addConvert(DataAccessConfigConvert configBuilderConvert) {
+    public SimpleDataAccessConfigBuilderFactory addConvert(DataAccessConfigConverter configBuilderConvert) {
         Objects.requireNonNull(configBuilderConvert);
         converts.add(configBuilderConvert);
         return this;
@@ -42,13 +41,13 @@ public class SimpleDataAccessConfigBuilderFactory implements DataAccessConfigBui
         return defaultSupportConvert;
     }
 
-    protected DataAccessConfigConvert createJsonConfig(String supportType, Class<? extends AbstractDataAccessConfig> clazz) {
+    protected DataAccessConfigConverter createJsonConfig(String supportType, Class<? extends AbstractDataAccessConfig> clazz) {
         return createConfig(supportType, (action, config) -> JSON.parseObject(config, clazz));
     }
 
 
-    protected DataAccessConfigConvert createConfig(String supportType, BiFunction<String, String, ? extends DataAccessConfig> function) {
-        return new DataAccessConfigConvert() {
+    protected DataAccessConfigConverter createConfig(String supportType, BiFunction<String, String, ? extends DataAccessConfig> function) {
+        return new DataAccessConfigConverter() {
             @Override
             public boolean isSupport(String type, String action, String config) {
                 return supportType.equals(type);
@@ -73,6 +72,10 @@ public class SimpleDataAccessConfigBuilderFactory implements DataAccessConfigBui
             converts.add(createJsonConfig(DENY_FIELDS, SimpleFieldFilterDataAccessConfig.class));
         }
 
+        if (defaultSupportConvert.contains(DIMENSION_SCOPE)) {
+            converts.add(createJsonConfig(DIMENSION_SCOPE, DimensionDataAccessConfig.class));
+        }
+
         if (defaultSupportConvert.contains(OWN_CREATED)) {
             converts.add(createConfig(OWN_CREATED, (action, config) -> new SimpleOwnCreatedDataAccessConfig(action)));
         }

+ 92 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/RedisUserTokenManager.java

@@ -0,0 +1,92 @@
+package org.hswebframework.web.authorization.token;
+
+import org.springframework.data.redis.core.ReactiveHashOperations;
+import org.springframework.data.redis.core.ReactiveRedisOperations;
+import org.springframework.data.redis.core.ReactiveSetOperations;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class RedisUserTokenManager implements UserTokenManager {
+
+    ReactiveRedisOperations<Object, Object> operations;
+
+    ReactiveHashOperations<String, String, UserToken> userTokenStore;
+
+    ReactiveSetOperations<String, String> userTokenMapping;
+
+    Map<String,UserToken> localCache=new ConcurrentHashMap<>();
+
+    @Override
+    public Mono<UserToken> getByToken(String token) {
+
+        return null;
+    }
+
+    @Override
+    public Flux<UserToken> getByUserId(String userId) {
+        return null;
+    }
+
+    @Override
+    public Mono<Boolean> userIsLoggedIn(String userId) {
+        return null;
+    }
+
+    @Override
+    public Mono<Boolean> tokenIsLoggedIn(String token) {
+        return null;
+    }
+
+    @Override
+    public Mono<Integer> totalUser() {
+        return null;
+    }
+
+    @Override
+    public Mono<Integer> totalToken() {
+        return null;
+    }
+
+    @Override
+    public Flux<UserToken> allLoggedUser() {
+        return null;
+    }
+
+    @Override
+    public Mono<Void> signOutByUserId(String userId) {
+        return null;
+    }
+
+    @Override
+    public Mono<Void> signOutByToken(String token) {
+        return null;
+    }
+
+    @Override
+    public Mono<Void> changeUserState(String userId, TokenState state) {
+        return null;
+    }
+
+    @Override
+    public Mono<Void> changeTokenState(String token, TokenState state) {
+        return null;
+    }
+
+    @Override
+    public Mono<UserToken> signIn(String token, String type, String userId, long maxInactiveInterval) {
+        return null;
+    }
+
+    @Override
+    public Mono<Void> touch(String token) {
+        return null;
+    }
+
+    @Override
+    public Mono<Void> checkExpiredToken() {
+        return null;
+    }
+}

+ 19 - 0
hsweb-authorization/hsweb-authorization-basic/pom.xml

@@ -30,6 +30,12 @@
             <artifactId>spring-boot-starter-aop</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.hswebframework.web</groupId>
+            <artifactId>hsweb-commons-crud</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>org.hswebframework.web</groupId>
             <artifactId>hsweb-access-logging-api</artifactId>
@@ -45,6 +51,7 @@
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-webmvc</artifactId>
+            <optional>true</optional>
         </dependency>
 
         <dependency>
@@ -73,6 +80,18 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot.experimental</groupId>
+            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.r2dbc</groupId>
+            <artifactId>r2dbc-h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-aspects</artifactId>

+ 1 - 0
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java

@@ -70,6 +70,7 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor
                     context.setAuthentication(auth);
                     Function<Runnable, Publisher> afterRuner = runnable -> {
                         MethodInterceptorContext interceptorContext = holder.createParamContext(invoker.get());
+                        context.setParamContext(interceptorContext);
                         runnable.run();
                         return (Publisher<?>) interceptorContext.getInvokeResult();
                     };

+ 3 - 0
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java

@@ -163,6 +163,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
         resource.setId(ann.id());
         resource.setName(ann.name());
         resource.setLogical(ann.logical());
+        resource.setPhased(ann.phased());
         resource.setDescription(String.join("\n", ann.description()));
         for (ResourceAction action : ann.actions()) {
             putAnnotation(resource, action);
@@ -193,6 +194,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
             typeDefinition.setId(dataAccessType.id());
             typeDefinition.setName(dataAccessType.name());
             typeDefinition.setController(dataAccessType.controller());
+            typeDefinition.setConfiguration(dataAccessType.configuration());
             typeDefinition.setDescription(String.join("\n", dataAccessType.description()));
         }
         definition.getDataAccess()
@@ -205,6 +207,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
         typeDefinition.setId(dataAccessType.id());
         typeDefinition.setName(dataAccessType.name());
         typeDefinition.setController(dataAccessType.controller());
+        typeDefinition.setConfiguration(dataAccessType.configuration());
         typeDefinition.setDescription(String.join("\n", dataAccessType.description()));
         definition.getDataAccess()
                 .getDataAccessTypes()

+ 60 - 0
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/DataAccessHandlerContext.java

@@ -0,0 +1,60 @@
+package org.hswebframework.web.authorization.basic.handler.access;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
+import org.hswebframework.utils.ClassUtils;
+import org.hswebframework.web.aop.MethodInterceptorContext;
+import org.hswebframework.web.authorization.Authentication;
+import org.hswebframework.web.authorization.Dimension;
+import org.hswebframework.web.authorization.DimensionType;
+import org.hswebframework.web.authorization.define.AuthorizingContext;
+import org.hswebframework.web.crud.web.reactive.*;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class DataAccessHandlerContext {
+
+    private Class<?> entityType;
+
+    private ReactiveRepository<?, Object> repository;
+
+    private Authentication authentication;
+
+    private List<Dimension> dimensions;
+
+    private MethodInterceptorContext paramContext;
+
+    public static DataAccessHandlerContext of(AuthorizingContext context, String type) {
+        DataAccessHandlerContext requestContext = new DataAccessHandlerContext();
+        Authentication authentication = context.getAuthentication();
+        requestContext.setDimensions(authentication.getDimensions(type));
+        requestContext.setAuthentication(context.getAuthentication());
+        requestContext.setParamContext(context.getParamContext());
+
+        Object target = context.getParamContext().getTarget();
+        Class entityType = ClassUtils.getGenericType(org.springframework.util.ClassUtils.getUserClass(target));
+        if (entityType != Object.class) {
+            requestContext.setEntityType(entityType);
+        }
+
+        if (target instanceof ReactiveQueryController) {
+            requestContext.setRepository(((ReactiveQueryController) target).getRepository());
+        } else if (target instanceof ReactiveSaveController) {
+            requestContext.setRepository(((ReactiveSaveController) target).getRepository());
+        } else if (target instanceof ReactiveDeleteController) {
+            requestContext.setRepository(((ReactiveDeleteController) target).getRepository());
+        } else if (target instanceof ReactiveServiceQueryController) {
+            requestContext.setRepository(((ReactiveServiceQueryController) target).getService().getRepository());
+        } else if (target instanceof ReactiveServiceSaveController) {
+            requestContext.setRepository(((ReactiveServiceSaveController) target).getService().getRepository());
+        } else if (target instanceof ReactiveServiceDeleteController) {
+            requestContext.setRepository(((ReactiveServiceDeleteController) target).getService().getRepository());
+        }
+        // TODO: 2019-11-18  not reactive implements
+
+        return requestContext;
+    }
+}

+ 2 - 1
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/DefaultDataAccessController.java

@@ -30,7 +30,8 @@ public final class DefaultDataAccessController implements DataAccessController {
             throw new UnsupportedOperationException();
         }
         this.parent = parent;
-                addHandler(new FieldFilterDataAccessHandler());
+                addHandler(new FieldFilterDataAccessHandler())
+                .addHandler(new DimensionDataAccessHandler());
     }
 
     @Override

+ 382 - 0
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/DimensionDataAccessHandler.java

@@ -0,0 +1,382 @@
+package org.hswebframework.web.authorization.basic.handler.access;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.hswebframework.ezorm.core.param.Param;
+import org.hswebframework.ezorm.core.param.QueryParam;
+import org.hswebframework.web.api.crud.entity.Entity;
+import org.hswebframework.web.api.crud.entity.QueryParamEntity;
+import org.hswebframework.web.authorization.Authentication;
+import org.hswebframework.web.authorization.Dimension;
+import org.hswebframework.web.authorization.Permission;
+import org.hswebframework.web.authorization.access.DataAccessConfig;
+import org.hswebframework.web.authorization.access.DataAccessHandler;
+import org.hswebframework.web.authorization.annotation.DimensionDataAccess;
+import org.hswebframework.web.authorization.define.AuthorizingContext;
+import org.hswebframework.web.authorization.exception.AccessDenyException;
+import org.hswebframework.web.authorization.simple.DimensionDataAccessConfig;
+import org.hswebframework.web.bean.FastBeanCopier;
+import org.hswebframework.web.utils.AnnotationUtils;
+import org.reactivestreams.Publisher;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Slf4j
+public class DimensionDataAccessHandler implements DataAccessHandler {
+    @Override
+    public boolean isSupport(DataAccessConfig access) {
+        return access instanceof DimensionDataAccessConfig;
+    }
+
+    @Override
+    public boolean handle(DataAccessConfig access, AuthorizingContext context) {
+        DimensionDataAccessConfig config = ((DimensionDataAccessConfig) access);
+        DataAccessHandlerContext requestContext = DataAccessHandlerContext.of(context, config.getScopeType());
+        if (!checkSupported(config, requestContext)) {
+            return false;
+        }
+        switch (access.getAction()) {
+            case Permission.ACTION_QUERY:
+            case Permission.ACTION_GET:
+                return doHandleQuery(config, requestContext);
+            case Permission.ACTION_ADD:
+            case Permission.ACTION_SAVE:
+            case Permission.ACTION_UPDATE:
+                return doHandleUpdate(config, requestContext);
+            case Permission.ACTION_DELETE:
+                return doHandleDelete(config, requestContext);
+            default:
+                if (log.isDebugEnabled()) {
+                    log.debug("data access [{}] not support for {}", config.getType().getId(), access.getAction());
+                }
+                return true;
+        }
+
+    }
+
+    @SneakyThrows
+    protected String getProperty(DimensionDataAccessConfig cfg,
+                                 DataAccessHandlerContext ct) {
+        return Optional.ofNullable(
+                getMappingInfo(ct).get(cfg.getScopeType()))
+                .map(MappingInfo::getProperty)
+                .orElseGet(() -> {
+                    log.warn("{} not supported dimension data access", ct.getParamContext().getMethod());
+                    return null;
+                });
+    }
+
+    protected boolean checkSupported(DimensionDataAccessConfig cfg, DataAccessHandlerContext ctx) {
+        Authentication authentication = ctx.getAuthentication();
+
+        /*
+            DataAccessHelper.assert()
+         */
+        if (CollectionUtils.isEmpty(ctx.getDimensions())) {
+            log.warn("user:[{}] dimension not setup", authentication.getUser().getId());
+            return false;
+        }
+
+        if (!getMappingInfo(ctx).containsKey(cfg.getScopeType())) {
+            log.warn("{} not supported dimension data access.see annotation: @DimensionDataAccess", ctx.getParamContext().getMethod());
+            return false;
+        }
+
+        return true;
+    }
+
+    protected boolean doHandleDelete(DimensionDataAccessConfig cfg,
+                                     DataAccessHandlerContext context) {
+
+
+        // TODO: 2019-11-18
+        return doHandleUpdate(cfg, context);
+
+    }
+
+    @SuppressWarnings("all")
+    protected Object handleUpdateById(DimensionDataAccessConfig config,
+                                      DataAccessHandlerContext context,
+                                      MappingInfo mappingInfo,
+                                      Object id) {
+        List<Dimension> dimensions = context.getDimensions();
+
+        Set<Object> scope = CollectionUtils.isNotEmpty(config.getScope()) ?
+                config.getScope() :
+                dimensions
+                        .stream()
+                        .map(Dimension::getId)
+                        .collect(Collectors.toSet());
+
+        Function<Collection<Object>, Mono<Void>> reactiveCheck = obj -> context
+                .getRepository()
+                .findById(obj)
+                .doOnNext(r -> {
+                    Object val = FastBeanCopier.copy(r, new HashMap<>(), FastBeanCopier.include(mappingInfo.getProperty()))
+                            .get(mappingInfo.getProperty());
+                    if (!StringUtils.isEmpty(val)
+                            && !scope.contains(val)) {
+                        throw new AccessDenyException();
+                    }
+                })
+                .then();
+        if (id instanceof Publisher) {
+            if (id instanceof Mono) {
+                return ((Mono) id)
+                        .flatMap(r -> reactiveCheck.apply(r instanceof Collection ? ((Collection) r) : Collections.singleton(r)))
+                        .then((Mono) id);
+            }
+            if (id instanceof Flux) {
+                return ((Flux) id)
+                        .collectList()
+                        .flatMap(reactiveCheck)
+                        .thenMany((Flux) id);
+            }
+        }
+        Collection<Object> idVal = id instanceof Collection ? ((Collection) id) : Collections.singleton(id);
+
+        Object result = context.getParamContext().getInvokeResult();
+        if (result instanceof Mono) {
+            context.getParamContext()
+                    .setInvokeResult(((Mono) result)
+                            .flatMap(res -> {
+                                return reactiveCheck.apply(idVal).thenReturn(res);
+                            }));
+        } else if (result instanceof Flux) {
+            context.getParamContext()
+                    .setInvokeResult(((Flux) result)
+                            .flatMap(res -> {
+                                return reactiveCheck.apply(idVal).thenReturn(res);
+                            }));
+        } else {
+            // TODO: 2019-11-19 非响应式处理
+        }
+        return id;
+    }
+
+    protected boolean doHandleUpdate(DimensionDataAccessConfig cfg,
+                                     DataAccessHandlerContext context) {
+        MappingInfo info = getMappingInfo(context).get(cfg.getScopeType());
+        if (info != null) {
+            if (info.idParamIndex != -1) {
+                Object param = context.getParamContext().getArguments()[info.idParamIndex];
+                context.getParamContext().getArguments()[info.idParamIndex] = handleUpdateById(cfg, context, info, param);
+                return true;
+            }
+        } else {
+            return true;
+        }
+
+        boolean reactive = context.getParamContext()
+                .handleReactiveArguments(publisher -> {
+                    if (publisher instanceof Mono) {
+                        return Mono.from(publisher)
+                                .flatMap(payload -> applyReactiveUpdatePayload(cfg, info, Collections.singleton(payload), context)
+                                        .thenReturn(payload));
+                    }
+                    if (publisher instanceof Flux) {
+                        return Flux.from(publisher)
+                                .collectList()
+                                .flatMapMany(list ->
+                                        applyReactiveUpdatePayload(cfg, info, list, context)
+                                                .flatMapIterable(v -> list));
+                    }
+
+                    return publisher;
+                });
+
+        if (!reactive) {
+            applyUpdatePayload(cfg, info, Arrays
+                    .stream(context.getParamContext().getArguments())
+                    .flatMap(obj -> {
+                        if (obj instanceof Collection) {
+                            return ((Collection<?>) obj).stream();
+                        }
+                        return Stream.of(obj);
+                    })
+                    .filter(Entity.class::isInstance)
+                    .collect(Collectors.toSet()), context);
+
+            return true;
+        }
+        return true;
+
+    }
+
+    protected void applyUpdatePayload(DimensionDataAccessConfig config,
+                                      MappingInfo mappingInfo,
+                                      Collection<?> payloads,
+                                      DataAccessHandlerContext context) {
+        List<Dimension> dimensions = context.getDimensions();
+
+        Set<Object> scope = CollectionUtils.isNotEmpty(config.getScope()) ?
+                config.getScope() :
+                dimensions
+                        .stream()
+                        .map(Dimension::getId)
+                        .collect(Collectors.toSet());
+
+        for (Object payload : payloads) {
+            if (!(payload instanceof Entity)) {
+                continue;
+            }
+            if (payload instanceof Param) {
+                applyQueryParam(config, context, ((Param) payload));
+                continue;
+            }
+            String property = mappingInfo.getProperty();
+            Map<String, Object> map = FastBeanCopier.copy(payload, new HashMap<>(), FastBeanCopier.include(property));
+            Object value = map.get(property);
+            if (StringUtils.isEmpty(value)) {
+                if (dimensions.size() == 1) {
+                    map.put(property, dimensions.get(0).getId());
+                    FastBeanCopier.copy(map, payload, property);
+                }
+                continue;
+            }
+            if (CollectionUtils.isNotEmpty(scope)) {
+                if (!scope.contains(value)) {
+                    throw new AccessDenyException();
+                }
+            }
+        }
+    }
+
+    protected Mono<Void> applyReactiveUpdatePayload(DimensionDataAccessConfig config,
+                                                    MappingInfo info,
+                                                    Collection<?> payloads,
+                                                    DataAccessHandlerContext context) {
+
+        return Mono.fromRunnable(() -> applyUpdatePayload(config, info, payloads, context));
+    }
+
+    protected boolean doHandleQuery(DimensionDataAccessConfig cfg, DataAccessHandlerContext requestContext) {
+        boolean reactive = requestContext.getParamContext().handleReactiveArguments(publisher -> {
+            if (publisher instanceof Mono) {
+                return Mono
+                        .from(publisher)
+                        .flatMap(param -> this
+                                .applyReactiveQueryParam(cfg, requestContext, param)
+                                .thenReturn(param));
+            }
+
+            return publisher;
+        });
+
+        if (!reactive) {
+            Object[] args = requestContext.getParamContext().getArguments();
+            this.applyQueryParam(cfg, requestContext, args);
+        }
+        return true;
+    }
+
+    protected String getTermType(DimensionDataAccessConfig cfg) {
+        return "in";
+    }
+
+    protected void applyQueryParam(DimensionDataAccessConfig cfg,
+                                   DataAccessHandlerContext requestContext,
+                                   Param param) {
+        Set<Object> scope = CollectionUtils.isNotEmpty(cfg.getScope()) ?
+                cfg.getScope() :
+                requestContext.getDimensions()
+                        .stream()
+                        .map(Dimension::getId)
+                        .collect(Collectors.toSet());
+
+        QueryParamEntity entity = new QueryParamEntity();
+        entity.setTerms(new ArrayList<>(param.getTerms()));
+        entity.toNestQuery(query ->
+                query.where(
+                        getProperty(cfg, requestContext),
+                        getTermType(cfg),
+                        scope));
+        param.setTerms(entity.getTerms());
+    }
+
+    protected void applyQueryParam(DimensionDataAccessConfig cfg,
+                                   DataAccessHandlerContext requestContext,
+                                   Object... params) {
+        for (Object param : params) {
+            if (param instanceof QueryParam) {
+                applyQueryParam(cfg, requestContext, (QueryParam) param);
+            }
+        }
+    }
+
+    protected Mono<Void> applyReactiveQueryParam(DimensionDataAccessConfig cfg,
+                                                 DataAccessHandlerContext requestContext,
+                                                 Object... param) {
+
+
+        return Mono.fromRunnable(() -> applyQueryParam(cfg, requestContext, param));
+    }
+
+    private Map<Method, Map<String, MappingInfo>> cache = new ConcurrentHashMap<>();
+
+
+    public Map<String, MappingInfo> getMappingInfo(DataAccessHandlerContext context) {
+        return getMappingInfo(ClassUtils.getUserClass(context.getParamContext().getTarget()), context.getParamContext().getMethod());
+
+    }
+
+    private Set<Class<? extends Annotation>> ann = new HashSet<>(Arrays.asList(DimensionDataAccess.class, DimensionDataAccess.Mapping.class));
+
+
+    private Map<String, MappingInfo> getMappingInfo(Class target, Method method) {
+
+        return cache.computeIfAbsent(method, m -> {
+            Set<Annotation> methodAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(method, ann);
+            Set<Annotation> classAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(target, ann);
+
+            if (CollectionUtils.isEmpty(methodAnnotation)) {
+                return Collections.emptyMap();
+            }
+            List<Annotation> all = new ArrayList<>(classAnnotation);
+            all.addAll(methodAnnotation);
+
+            Map<String, MappingInfo> mappingInfoMap = new HashMap<>();
+            for (Annotation annotation : all) {
+                if (annotation instanceof DimensionDataAccess) {
+                    for (DimensionDataAccess.Mapping mapping : ((DimensionDataAccess) annotation).mapping()) {
+                        mappingInfoMap.put(mapping.dimensionType(), MappingInfo.of(mapping));
+                    }
+                }
+                if (annotation instanceof DimensionDataAccess.Mapping) {
+                    mappingInfoMap.put(((DimensionDataAccess.Mapping) annotation).dimensionType(), MappingInfo.of(((DimensionDataAccess.Mapping) annotation)));
+                }
+            }
+            return mappingInfoMap;
+        });
+    }
+
+    @Getter
+    @Setter
+    @AllArgsConstructor
+    static class MappingInfo {
+        String dimension;
+
+        String property;
+
+        int idParamIndex;
+
+        static MappingInfo of(DimensionDataAccess.Mapping mapping) {
+            return new MappingInfo(mapping.dimensionType(), mapping.property(), mapping.idParamIndex());
+        }
+    }
+}

+ 1 - 0
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/access/FieldFilterDataAccessHandler.java

@@ -39,6 +39,7 @@ public class FieldFilterDataAccessHandler implements DataAccessHandler {
             case Permission.ACTION_GET:
                 return doQueryAccess(filterDataAccessConfig, context);
             case Permission.ACTION_ADD:
+            case Permission.ACTION_SAVE:
             case Permission.ACTION_UPDATE:
                 return doUpdateAccess(filterDataAccessConfig, context);
             default:

+ 80 - 25
hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingControllerTest.java

@@ -2,36 +2,20 @@ package org.hswebframework.web.authorization.basic.aop;
 
 import org.hswebframework.ezorm.core.param.Param;
 import org.hswebframework.ezorm.core.param.QueryParam;
-import org.hswebframework.web.authorization.Authentication;
-import org.hswebframework.web.authorization.ReactiveAuthenticationHolder;
-import org.hswebframework.web.authorization.ReactiveAuthenticationSupplier;
-import org.hswebframework.web.authorization.User;
-import org.hswebframework.web.authorization.basic.handler.access.FieldFilterDataAccessHandler;
-import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenParser;
+import org.hswebframework.ezorm.core.param.Term;
+import org.hswebframework.web.authorization.*;
 import org.hswebframework.web.authorization.exception.AccessDenyException;
-import org.hswebframework.web.authorization.exception.UnAuthorizedException;
-import org.hswebframework.web.authorization.simple.SimpleAuthentication;
-import org.hswebframework.web.authorization.simple.SimpleFieldFilterDataAccessConfig;
-import org.hswebframework.web.authorization.simple.SimplePermission;
-import org.hswebframework.web.authorization.simple.SimpleUser;
-import org.hswebframework.web.authorization.token.ParsedToken;
-import org.junit.Before;
+import org.hswebframework.web.authorization.simple.*;
 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.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-
-import static org.junit.Assert.*;
+import java.util.*;
+import java.util.function.Function;
 
 @RunWith(SpringJUnit4ClassRunner.class)
 @SpringBootTest(classes = TestApplication.class)
@@ -76,10 +60,10 @@ public class AopAuthorizingControllerTest {
     }
 
     @Test
-    public void testFiledDeny(){
+    public void testFiledDeny() {
         SimpleAuthentication authentication = new SimpleAuthentication();
 
-        SimpleFieldFilterDataAccessConfig config=new SimpleFieldFilterDataAccessConfig();
+        SimpleFieldFilterDataAccessConfig config = new SimpleFieldFilterDataAccessConfig();
         config.setAction("query");
         config.setFields(new HashSet<>(Arrays.asList("name")));
 
@@ -104,13 +88,84 @@ public class AopAuthorizingControllerTest {
         testController.queryUser(new QueryParam())
                 .map(Param::getExcludes)
                 .as(StepVerifier::create)
-                .expectNextMatches(f->f.contains("name"))
+                .expectNextMatches(f -> f.contains("name"))
                 .verifyComplete();
 
         testController.queryUser(Mono.just(new QueryParam()))
                 .map(Param::getExcludes)
                 .as(StepVerifier::create)
-                .expectNextMatches(f->f.contains("name"))
+                .expectNextMatches(f -> f.contains("name"))
                 .verifyComplete();
     }
+
+    @Test
+    public void testDimensionDataAccess() {
+        SimpleAuthentication authentication = new SimpleAuthentication();
+
+        DimensionDataAccessConfig config = new DimensionDataAccessConfig();
+        config.setAction("query");
+        config.setScopeType("role");
+
+        DimensionDataAccessConfig config2 = new DimensionDataAccessConfig();
+        config2.setAction("save");
+        config2.setScopeType("role");
+        ReactiveAuthenticationHolder.addSupplier(new ReactiveAuthenticationSupplier() {
+            @Override
+            public Mono<Authentication> get(String userId) {
+                return Mono.empty();
+            }
+
+            @Override
+            public Mono<Authentication> get() {
+                return Mono.just(authentication);
+            }
+        });
+
+        authentication.setUser(SimpleUser.builder().id("test").username("test").build());
+        authentication.setPermissions(Arrays.asList(SimplePermission.builder()
+                .actions(new HashSet<>(Arrays.asList("query", "save")))
+                .dataAccesses(new HashSet<>(Arrays.asList(config, config2)))
+                .id("test").build()));
+        authentication.setDimensions(Collections.singletonList(Dimension.of("test", "test", DefaultDimensionType.role)));
+
+        testController.queryUserByDimension(Mono.just(new QueryParam()))
+                .map(Param::getTerms)
+                .flatMapIterable(Function.identity())
+                .next()
+                .map(Term::getValue)
+                .<Collection<Object>>map(Collection.class::cast)
+                .flatMapIterable(Function.identity())
+                .next()
+                .as(StepVerifier::create)
+                .expectNextMatches("test"::equals)
+                .verifyComplete();
+
+        TestEntity testEntity = new TestEntity();
+        testEntity.setRoleId("123");
+
+        testController.save(Mono.just(testEntity))
+                .as(StepVerifier::create)
+                .expectError(AccessDenyException.class)
+                .verify();
+
+        testController.add(Mono.just(testEntity))
+                .as(StepVerifier::create)
+                .expectNextCount(1)
+                .verifyComplete();
+
+        testController.update(testEntity.getId(),Mono.just(testEntity))
+                .as(StepVerifier::create)
+                .expectError(AccessDenyException.class)
+                .verify();
+
+        testEntity = new TestEntity();
+        testEntity.setRoleId("test");
+
+        testController.save(Mono.just(testEntity))
+                .as(StepVerifier::create)
+                .expectNextCount(1)
+                .verifyComplete();
+
+
+    }
 }

+ 2 - 0
hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestApplication.java

@@ -1,11 +1,13 @@
 package org.hswebframework.web.authorization.basic.aop;
 
 import org.hswebframework.web.authorization.basic.configuration.EnableAopAuthorize;
+import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
 @SpringBootApplication
 @EnableAopAuthorize
+@EnableEasyormRepository("org.hswebframework.web.authorization.basic.aop")
 public class TestApplication {
 
     public static void main(String[] args) {

+ 33 - 4
hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestController.java

@@ -1,18 +1,21 @@
 package org.hswebframework.web.authorization.basic.aop;
 
 import org.hswebframework.ezorm.core.param.QueryParam;
+import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
 import org.hswebframework.web.authorization.Authentication;
 import org.hswebframework.web.authorization.User;
-import org.hswebframework.web.authorization.access.DataAccessConfig;
 import org.hswebframework.web.authorization.annotation.*;
 import org.hswebframework.web.authorization.define.Phased;
 import org.hswebframework.web.authorization.exception.UnAuthorizedException;
+import org.hswebframework.web.crud.web.reactive.ReactiveCrudController;
+import org.hswebframework.web.crud.web.reactive.ReactiveQueryController;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RestController;
 import reactor.core.publisher.Mono;
 
 @RestController
 @Resource(id = "test", name = "测试")
-public class TestController {
+public class TestController implements ReactiveCrudController<TestEntity, String> {
 
     @QueryAction
     public Mono<User> getUser() {
@@ -28,15 +31,41 @@ public class TestController {
                 .map(Authentication::getUser);
     }
 
-    @QueryAction(dataAccess = @DataAccess(type = @DataAccessType(id= DataAccessConfig.DefaultType.DENY_FIELDS,name = "禁止访问字段")))
+    @QueryAction
+    @FieldDataAccess
     public Mono<QueryParam> queryUser(QueryParam queryParam) {
         return Mono.just(queryParam);
     }
 
-    @QueryAction(dataAccess = @DataAccess(type = @DataAccessType(id= DataAccessConfig.DefaultType.DENY_FIELDS,name = "禁止访问字段")))
+    @QueryAction
+    @FieldDataAccess
     public Mono<QueryParam> queryUser(Mono<QueryParam> queryParam) {
         return queryParam;
     }
 
+    @QueryAction
+    @TestDataAccess
+    public Mono<QueryParam> queryUserByDimension(Mono<QueryParam> queryParam) {
+        return queryParam;
+    }
 
+    @SaveAction
+    @TestDataAccess
+    public Mono<TestEntity> save(Mono<TestEntity> param) {
+        return param;
+    }
+
+    @Override
+    @TestDataAccess(idParamIndex = 0,phased = Phased.after)
+    public Mono<Boolean> update(String id, Mono<TestEntity> payload) {
+        return ReactiveCrudController.super.update(id, payload);
+    }
+
+    @Autowired
+    ReactiveRepository<TestEntity, String> reactiveRepository;
+
+    @Override
+    public ReactiveRepository<TestEntity, String> getRepository() {
+        return reactiveRepository;
+    }
 }

+ 22 - 0
hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestDataAccess.java

@@ -0,0 +1,22 @@
+package org.hswebframework.web.authorization.basic.aop;
+
+import org.hswebframework.web.authorization.annotation.DimensionDataAccess;
+import org.hswebframework.web.authorization.define.Phased;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
+@DimensionDataAccess
+@DimensionDataAccess.Mapping(dimensionType = "role", property = "roleId")
+public @interface TestDataAccess {
+
+    @AliasFor(annotation = DimensionDataAccess.Mapping.class)
+    int idParamIndex() default -1;
+
+    @AliasFor(annotation = DimensionDataAccess.class)
+    Phased phased() default Phased.before;
+
+}

+ 20 - 0
hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/TestEntity.java

@@ -0,0 +1,20 @@
+package org.hswebframework.web.authorization.basic.aop;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.api.crud.entity.GenericEntity;
+import reactor.core.publisher.Mono;
+
+import javax.persistence.Column;
+import javax.persistence.Table;
+
+@Getter
+@Setter
+@Table(name = "test_entity")
+public class TestEntity extends GenericEntity<String> {
+
+    @Column
+    private String roleId;
+
+
+}

+ 6 - 1
hsweb-authorization/hsweb-authorization-basic/src/test/resources/application.yml

@@ -7,4 +7,9 @@ hsweb:
       permissions-simple:
           user-token:
             - get
-            - update
+            - update
+easyorm:
+  dialect: h2
+logging:
+  level:
+    org.hswebframework: debug

+ 3 - 0
hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/QueryParamEntity.java

@@ -101,6 +101,9 @@ public class QueryParamEntity extends QueryParam {
         if (null != before) {
             before.accept(query);
         }
+        if(terms.isEmpty()){
+            return query;
+        }
         return query
                 .nest()
                 .each(terms, NestConditional::accept)

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

@@ -18,6 +18,7 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 import java.util.List;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -46,15 +47,14 @@ public class DefaultDimensionService
     }
 
     @Override
-    public Flux<DimensionType> getAllType() {
+    public Flux<DimensionTypeEntity> getAllType() {
         return dimensionTypeRepository
                 .createQuery()
-                .fetch()
-                .cast(DimensionType.class);
+                .fetch();
     }
 
     @Override
-    public Flux<Dimension> getDimensionByUserId(String userId) {
+    public Flux<DynamicDimension> getDimensionByUserId(String userId) {
         return getAllType()
                 .collect(Collectors.toMap(DimensionType::getId, Function.identity()))
                 .flatMapMany(typeGrouping ->
@@ -62,7 +62,19 @@ public class DefaultDimensionService
                                 .createQuery()
                                 .where(DimensionUserEntity::getUserId, userId)
                                 .fetch()
-                                .map(entity -> DynamicDimension.of(entity, typeGrouping.get(entity.getDimensionTypeId()))));
+                                .collectList()
+                                .flatMapMany(list -> {
+                                    //查询所有的维度
+                                    return this.findById(Flux.fromIterable(list.stream()
+                                            .map(DimensionUserEntity::getDimensionId)
+                                            .collect(Collectors.toSet())))
+                                            .map(dimension ->
+                                                    DynamicDimension.of(dimension, typeGrouping.get(dimension.getTypeId()))
+                                            )
+                                            ;
+
+                                })
+                );
     }
 
     @Override

+ 11 - 5
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DynamicDimension.java

@@ -4,8 +4,10 @@ import lombok.Getter;
 import lombok.Setter;
 import org.hswebframework.web.authorization.Dimension;
 import org.hswebframework.web.authorization.DimensionType;
+import org.hswebframework.web.system.authorization.api.entity.DimensionEntity;
 import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity;
 
+import java.util.HashMap;
 import java.util.Map;
 
 @Getter
@@ -18,12 +20,16 @@ public class DynamicDimension implements Dimension {
     private Map<String, Object> options;
 
 
-    public static DynamicDimension of(DimensionUserEntity entity,
-                                      DimensionType type){
-        DynamicDimension dynamicDimension=new DynamicDimension();
-        dynamicDimension.setId(entity.getDimensionId());
-        dynamicDimension.setName(entity.getDimensionName());
+    public static DynamicDimension of(DimensionEntity entity,
+                                      DimensionType type) {
+        DynamicDimension dynamicDimension = new DynamicDimension();
+        dynamicDimension.setId(entity.getId());
+        dynamicDimension.setName(entity.getName());
         dynamicDimension.setType(type);
+        Map<String, Object> options = new HashMap<>();
+        options.put("parentId", entity.getParentId());
+        options.put("path", entity.getPath());
+        dynamicDimension.setOptions(options);
         return dynamicDimension;
 
     }