Browse Source

优化权限管理

zhou-hao 5 years ago
parent
commit
16e4baa732
12 changed files with 153 additions and 79 deletions
  1. 8 0
      hsweb-authorization/hsweb-authorization-api/pom.xml
  2. 0 8
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java
  3. 1 6
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java
  4. 1 1
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java
  5. 5 3
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java
  6. 14 0
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/DataAccessEntity.java
  7. 2 2
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java
  8. 27 1
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java
  9. 56 54
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java
  10. 4 2
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java
  11. 1 1
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java
  12. 34 1
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java

+ 8 - 0
hsweb-authorization/hsweb-authorization-api/pom.xml

@@ -18,6 +18,12 @@
             <version>${project.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-redis</artifactId>
+            <optional>true</optional>
+        </dependency>
+
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
@@ -34,10 +40,12 @@
             <artifactId>reactor-test</artifactId>
             <scope>test</scope>
         </dependency>
+
         <dependency>
             <groupId>io.swagger</groupId>
             <artifactId>swagger-annotations</artifactId>
         </dependency>
+
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>

+ 0 - 8
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java

@@ -51,14 +51,6 @@ public interface UserToken extends Serializable, Comparable<UserToken> {
 
     long getMaxInactiveInterval();
 
-    /**
-     * @return 是否正常
-     */
-    @Deprecated
-    default boolean isEffective() {
-        return isNormal();
-    }
-
     default boolean isNormal() {
         return getState() == TokenState.normal;
     }

+ 1 - 6
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java

@@ -71,12 +71,7 @@ public class UserTokenReactiveAuthenticationSupplier implements ReactiveAuthenti
                         context.get(ContextKey.of(ParsedToken.class))
                                 .map(t -> userTokenManager
                                         .getByToken(t.getToken())
-                                        .map(token -> {
-                                            if (!token.isNormal()) {
-                                                throw new UnAuthorizedException(token.getState());
-                                            }
-                                            return token;
-                                        }))
+                                        .filter(UserToken::validate))
                                 .map(tokenMono -> tokenMono
                                         .doOnNext(token->userTokenManager.touch(token.getToken()))
                                         .flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())))

+ 1 - 1
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java

@@ -15,7 +15,7 @@ import reactor.core.publisher.Mono;
  * @since 3.0.0-RC
  */
 
-@Order(Ordered.HIGHEST_PRECEDENCE)
+@Order(10)
 @AllArgsConstructor
 public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticationManagerProvider {
 

+ 5 - 3
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java

@@ -10,6 +10,7 @@ import reactor.core.publisher.Mono;
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
 @Getter
@@ -54,10 +55,11 @@ public class DefaultUserTokenGenPar implements ReactiveUserTokenGenerator, React
 
     @Override
     public Mono<ParsedToken> parseToken(ServerWebExchange exchange) {
-        String token =exchange.getRequest()
+        String token = Optional.ofNullable(exchange.getRequest()
                 .getHeaders()
-                .getFirst(headerName);
-        if(token==null){
+                .getFirst(headerName))
+                .orElseGet(() -> exchange.getRequest().getQueryParams().getFirst(":X_Access_Token"));
+        if (token == null) {
             return Mono.empty();
         }
         return Mono.just(new ParsedToken() {

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

@@ -3,6 +3,7 @@ package org.hswebframework.web.system.authorization.api.entity;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -17,4 +18,17 @@ public class DataAccessEntity {
     private String describe;
 
     private Map<String,Object> config;
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<>();
+        map.put("type",type);
+        map.put("action",action);
+        map.put("describe",describe);
+
+        if(config!=null){
+            map.putAll(config);
+        }
+
+        return map;
+    }
 }

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

@@ -32,13 +32,13 @@ public class UserEntity extends GenericEntity<String> implements RecordCreationE
 
     @Column(nullable = false)
     @ToString.Ignore(cover = false)
-    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
     @NotBlank(message = "密码不能为空", groups = CreateGroup.class)
     private String password;
 
     @Column(nullable = false)
     @ToString.Ignore(cover = false)
-    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
     private String salt;
 
     @Column

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

@@ -7,12 +7,15 @@ import org.hswebframework.web.authorization.DimensionType;
 import org.hswebframework.web.crud.service.GenericReactiveCrudService;
 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.reactivestreams.Publisher;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.StringUtils;
 import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 import java.util.List;
 import java.util.function.Function;
@@ -29,6 +32,9 @@ public class DefaultDimensionService
     @Autowired
     private ReactiveRepository<DimensionTypeEntity, String> dimensionTypeRepository;
 
+    @Autowired
+    private ReactiveRepository<AuthorizationSettingEntity, String> settingRepository;
+
     @Override
     public IDGenerator<String> getIDGenerator() {
         return IDGenerator.MD5;
@@ -57,7 +63,6 @@ public class DefaultDimensionService
                                 .where(DimensionUserEntity::getUserId, userId)
                                 .fetch()
                                 .map(entity -> DynamicDimension.of(entity, typeGrouping.get(entity.getDimensionTypeId()))));
-
     }
 
     @Override
@@ -70,4 +75,25 @@ public class DefaultDimensionService
                 .fetch()
                 .map(DimensionUserEntity::getUserId);
     }
+
+    @Override
+    public Mono<Integer> deleteById(Publisher<String> idPublisher) {
+        return Flux.from(idPublisher)
+                .collectList()
+                .flatMap(list -> super.deleteById(Flux.fromIterable(list))
+                        .then(dimensionUserRepository.createDelete() //删除维度用户关联
+                                .where()
+                                .in(DimensionUserEntity::getDimensionId, list)
+                                .execute())
+                        .then(findById(Flux.fromIterable(list))
+                                .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))
+                        ).thenReturn(list.size()));
+    }
+
 }

+ 56 - 54
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java

@@ -1,5 +1,6 @@
 package org.hswebframework.web.system.authorization.defaults.service;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
 import org.hswebframework.web.authorization.Authentication;
@@ -28,6 +29,7 @@ import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+@Slf4j
 public class DefaultReactiveAuthenticationInitializeService
         implements ReactiveAuthenticationInitializeService {
 
@@ -101,76 +103,76 @@ public class DefaultReactiveAuthenticationInitializeService
                                                     Map<String, List<AuthorizationSettingEntity>> settings) {
         Map<String, PermissionEntity> permissionMap = new HashMap<>();
         Map<String, SimplePermission> allowed = new HashMap<>();
+        try {
+            for (PermissionEntity permissionEntity : permissions.values()) {
+                permissionMap.put(permissionEntity.getId(), permissionEntity);
+                List<AuthorizationSettingEntity> permissionSettings = settings.get(permissionEntity.getId());
+                if (CollectionUtils.isEmpty(permissionSettings)) {
+                    continue;
+                }
+                permissionSettings.sort(Comparator.comparingInt(e -> e.getPriority() == null ? 0 : e.getPriority()));
+                SimplePermission permission = new SimplePermission();
+                permission.setId(permissionEntity.getId());
+                permission.setName(permissionEntity.getName());
+                Map<DataAccessType, DataAccessConfig> configs = new HashMap<>();
 
-        for (PermissionEntity permissionEntity : permissions.values()) {
-            permissionMap.put(permissionEntity.getId(), permissionEntity);
-            List<AuthorizationSettingEntity> permissionSettings = settings.get(permissionEntity.getId());
-            if (CollectionUtils.isEmpty(permissionSettings)) {
-                continue;
-            }
-            permissionSettings.sort(Comparator.comparingInt(e -> e.getPriority() == null ? 0 : e.getPriority()));
-            SimplePermission permission = new SimplePermission();
-            permission.setId(permissionEntity.getId());
-            permission.setName(permissionEntity.getName());
-            Map<DataAccessType, DataAccessConfig> configs = new HashMap<>();
+                for (AuthorizationSettingEntity permissionSetting : permissionSettings) {
 
-            for (AuthorizationSettingEntity permissionSetting : permissionSettings) {
+                    boolean merge = Boolean.TRUE.equals(permissionSetting.getMerge());
 
-                boolean merge = Boolean.TRUE.equals(permissionSetting.getMerge());
+                    if (!merge) {
+                        permission.getActions().clear();
+                    }
 
-                if (!merge) {
-                    permission.getActions().clear();
-                }
+                    if (permissionSetting.getDataAccesses() != null) {
+                        permissionSetting.getDataAccesses()
+                                .stream()
+                                .map(conf -> builderFactory.create().fromMap(conf.toMap()).build())
+                                .forEach(access -> configs.put(access.getType(), access));
+                    }
+                    if (CollectionUtils.isNotEmpty(permissionSetting.getActions())) {
+                        permission.getActions().addAll(permissionSetting.getActions());
+                    }
 
-                if (permissionSetting.getDataAccesses() != null) {
-                    permissionSetting.getDataAccesses()
-                            .stream()
-                            .map(conf -> builderFactory.create().fromMap(conf.getConfig()).build())
-                            .forEach(access -> configs.put(access.getType(), access));
-                }
-                if (CollectionUtils.isNotEmpty(permissionSetting.getActions())) {
-                    permission.getActions().addAll(permissionSetting.getActions());
                 }
-
+                allowed.put(permissionEntity.getId(), permission);
+                permission.setDataAccesses(new HashSet<>(configs.values()));
             }
-            allowed.put(permissionEntity.getId(), permission);
-            permission.setDataAccesses(new HashSet<>(configs.values()));
-        }
 
-        //处理关联权限
-        for (PermissionEntity permissionEntity : permissions.values()) {
-            SimplePermission allow = allowed.get(permissionEntity.getId());
-            if (allow == null || CollectionUtils.isEmpty(permissionEntity.getParents())) {
-                continue;
-            }
-            for (ParentPermission parent : permissionEntity.getParents()) {
-                if (StringUtils.isEmpty(parent.getPermission())) {
+            //处理关联权限
+            for (PermissionEntity permissionEntity : permissions.values()) {
+                SimplePermission allow = allowed.get(permissionEntity.getId());
+                if (allow == null || CollectionUtils.isEmpty(permissionEntity.getParents())) {
                     continue;
                 }
-                Set<String> pre = parent.getPreActions();
-                //满足前置条件
-                if (CollectionUtils.isEmpty(pre) || allow.getActions().containsAll(pre)) {
-                    PermissionEntity mergePermission = permissionMap.get(parent.getPermission());
-                    if (mergePermission == null) {
+                for (ParentPermission parent : permissionEntity.getParents()) {
+                    if (StringUtils.isEmpty(parent.getPermission())) {
                         continue;
                     }
-                    SimplePermission merge = allowed.get(parent.getPermission());
-                    if (merge == null) {
-                        merge = new SimplePermission();
-                        merge.setName(mergePermission.getName());
-                        merge.setId(mergePermission.getId());
-                        allowed.put(merge.getId(), merge);
-                    }
-                    if (CollectionUtils.isNotEmpty(parent.getActions())) {
-                        merge.getActions().addAll(parent.getActions());
+                    Set<String> pre = parent.getPreActions();
+                    //满足前置条件
+                    if (CollectionUtils.isEmpty(pre) || allow.getActions().containsAll(pre)) {
+                        PermissionEntity mergePermission = permissionMap.get(parent.getPermission());
+                        if (mergePermission == null) {
+                            continue;
+                        }
+                        SimplePermission merge = allowed.get(parent.getPermission());
+                        if (merge == null) {
+                            merge = new SimplePermission();
+                            merge.setName(mergePermission.getName());
+                            merge.setId(mergePermission.getId());
+                            allowed.put(merge.getId(), merge);
+                        }
+                        if (CollectionUtils.isNotEmpty(parent.getActions())) {
+                            merge.getActions().addAll(parent.getActions());
+                        }
                     }
                 }
             }
+            authentication.setPermissions(new ArrayList<>(allowed.values()));
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
         }
-
-
-        authentication.setPermissions(new ArrayList<>(allowed.values()));
-
         return authentication;
     }
 

+ 4 - 2
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java

@@ -12,9 +12,12 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.CacheManager;
 import org.springframework.cache.support.SimpleValueWrapper;
 import org.springframework.context.event.EventListener;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
 import reactor.core.publisher.Mono;
 
 @Slf4j
+@Order(100)
 public class DefaultReactiveAuthenticationManager implements ReactiveAuthenticationManagerProvider {
 
     @Autowired
@@ -65,7 +68,6 @@ public class DefaultReactiveAuthenticationManager implements ReactiveAuthenticat
                 .flatMap(_id -> Mono.justOrEmpty(cacheManager)
                         .map(cm -> cacheManager.<Authentication>getCache("user-auth"))
                         .flatMap(cache -> cache.mono(userId).onCacheMissResume(() -> initializeService.initUserAuthorization(userId)))
-                        .cast(Authentication.class)
-                        .switchIfEmpty(initializeService.initUserAuthorization(userId)));
+                        .cast(Authentication.class));
     }
 }

+ 1 - 1
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java

@@ -78,7 +78,7 @@ public class PermissionSynchronization implements CommandLineRunner {
                         .as(permissionRepository::save))
                 .doOnError(err -> log.warn("sync permission error", err))
                 .subscribe(l -> {
-                    log.warn("sync permission success:{}", l);
+                    log.info("sync permission success:{}", l);
                 });
 
     }

+ 34 - 1
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionUserController.java

@@ -1,19 +1,23 @@
 package org.hswebframework.web.system.authorization.defaults.webflux;
 
 import org.hswebframework.web.authorization.annotation.Authorize;
+import org.hswebframework.web.authorization.annotation.DeleteAction;
 import org.hswebframework.web.authorization.annotation.Resource;
 import org.hswebframework.web.crud.service.ReactiveCrudService;
 import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
 import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity;
 import org.hswebframework.web.system.authorization.defaults.service.DefaultDimensionUserService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
 
 @RestController
 @RequestMapping("/dimension-user")
 @Authorize
-@Resource(id = "dimension",name = "权限维度管理",group = "system")
+@Resource(id = "dimension", name = "权限维度管理", group = "system")
 public class WebFluxDimensionUserController implements ReactiveServiceCrudController<DimensionUserEntity, String> {
 
     @Autowired
@@ -23,4 +27,33 @@ public class WebFluxDimensionUserController implements ReactiveServiceCrudContro
     public ReactiveCrudService<DimensionUserEntity, String> getService() {
         return dimensionUserService;
     }
+
+
+    @DeleteAction
+    @DeleteMapping("/user/{userId}/dimension/{dimensionId}")
+    public Mono<Integer> deleteByUserAndDimensionId(@PathVariable String userId, @PathVariable String dimensionId) {
+        return dimensionUserService
+                .createDelete()
+                .where(DimensionUserEntity::getUserId, userId)
+                .and(DimensionUserEntity::getDimensionId, dimensionId)
+                .execute();
+    }
+
+    @DeleteAction
+    @DeleteMapping("/user/{userId}")
+    public Mono<Integer> deleteByUserId(@PathVariable String userId) {
+        return dimensionUserService
+                .createDelete()
+                .where(DimensionUserEntity::getUserId, userId)
+                .execute();
+    }
+
+    @DeleteAction
+    @DeleteMapping("/dimension/{dimensionId}")
+    public Mono<Integer> deleteByDimension(@PathVariable String dimensionId) {
+        return dimensionUserService
+                .createDelete()
+                .where(DimensionUserEntity::getDimensionId, dimensionId)
+                .execute();
+    }
 }