diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index d0fab5c2..f2a6055d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -55,7 +55,9 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RolePermissionCacheService; +import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasCommonDictService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -172,6 +174,8 @@ public class PrivateController { private ProductModuleDao productModuleDao; @Autowired private CacheWorkspaceProductJob cacheWorkspaceProductJob; + @Autowired + private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -820,11 +824,21 @@ public class PrivateController { .build(); List allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal()); - List roles = listRole(request); + List roles = listRole(ListRoleUserRelationParam.builder() + .personId(request.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(request.getWorkspaceId()) + .ouId(request.getOuId()) + .build())) + .needRole(true) + .build()); List productPermissions = listWorkspaceProductPermission(request); - List products = listProduct(productPermissions); + List productIds = productPermissions.stream() + .map(WorkspaceProductService.ProductPermission::getProductId) + .collect(Collectors.toList()); + List products = listProduct(productIds); Map> rolePermissions = listRolePermission(roles); @@ -835,6 +849,75 @@ public class PrivateController { .build()); } + @PostMapping("/api/private/featureResource/check") + public ApiResult checkFeatureResource(@RequestBody @Validated CheckFeatureResourceParam request) { + + SaasFeatureResourceService.ListSaasFeatureResourceCache listSaasFeatureResourceCache = SaasFeatureResourceService.ListSaasFeatureResourceCache.builder() + .terminals(Sets.newHashSet(request.getTerminal())) + .build(); + List allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal()); + + List roles = listRole(ListRoleUserRelationParam.builder() + .personId(request.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(request.getWorkspaceId()) + .ouId(request.getOuId()) + .build())) + .needRole(true) + .build()); + + List productFeatureSources = listWorkspaceProductFeatureResource(request); + + List productIds = productFeatureSources.stream() + .map(WorkspaceProductService.ProductFeatureSource::getProductId) + .collect(Collectors.toList()); + List products = listProduct(productIds); + + Map> roleFeatureResources = listRoleFeatureResource(roles); + + return ApiResult.ok(CheckFeatureResourceDTO.builder() + .products(products) + .roles(roles) + .uniCodeCheckResults(resolveUniCode(request, productFeatureSources, roleFeatureResources, roles, allFeatures)) + .build()); + } + + private UniCodeCheckResult resolveAdminRoleFeature(List adminRoles, + List productFeatureResources) { + if (CollectionUtils.isEmpty(adminRoles)) { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有管理员角色")) + .build(); + + } + + List reasons = Lists.newArrayList(); + Boolean authPermission = false; + + for (Role adminRole : adminRoles) { + + List adminPermissions = productFeatureResources.stream() + .filter(e -> Objects.equals(e.getCooperateType(), adminRole.getCooperateType().toString())) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(adminPermissions)) { + reasons.add("角色Id:" + adminRole.getRoleId() + + ";角色名字:" + adminRole.getRoleName() + + ";单位类型:" + adminRole.getCooperateType() + ";是管理员角色,有该权限code权限"); + authPermission = true; + } else { + reasons.add("角色Id:" + adminRole.getRoleId() + + ";角色名字:" + adminRole.getRoleName() + + ";单位类型:" + adminRole.getCooperateType() + ";没有该权限code权限"); + } + } + return UniCodeCheckResult.builder() + .authPermission(authPermission) + .reasons(reasons) + .build(); + } + private FeatureCodeCheckResult resolveAdminRole(List adminRoles, List productPermissions) { if (CollectionUtils.isEmpty(adminRoles)) { @@ -919,6 +1002,54 @@ public class PrivateController { .build(); } + private UniCodeCheckResult resolveNormalRoleFeature(List normalRoles, + List productFeatureResources, + Map> rolePermissions, + String uniCode) { + if (CollectionUtils.isEmpty(normalRoles)) { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有普通角色")) + .build(); + + } + + List reasons = Lists.newArrayList(); + Boolean authPermission = false; + + for (Role normalRole : normalRoles) { + List normalRolepermissions = rolePermissions.getOrDefault(normalRole.getRoleId(), Lists.newArrayList()) + .stream() + .filter(e -> Objects.equals(e.getUniCode(), uniCode)) + .collect(Collectors.toList()); + + Set productCooperateTypes = productFeatureResources.stream() + .map(e -> e.getCooperateType()) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(normalRolepermissions)) { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";没有该权限code权限"); + } else if (productCooperateTypes.contains(normalRole.getCooperateType().toString())) { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";有该权限code权限;有该权限的产品的单位类型有" + + JSON.toJSONString(productCooperateTypes)); + authPermission = true; + } else { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";有该权限code权限;有该权限的产品的单位类型有" + + JSON.toJSONString(productCooperateTypes)); + } + } + return UniCodeCheckResult.builder() + .authPermission(authPermission) + .reasons(reasons) + .build(); + } + private FeatureCodeCheckResult resolveNotAuth(List productPermissions, String featureCode, List allFeatures) { @@ -974,6 +1105,61 @@ public class PrivateController { } } + private UniCodeCheckResult resolveNotAuthFeature(List productFeatureResources, + String uniCode, + List allFeatures) { + // 直接配置成免授权的权限点 + List notAuthFeatures = allFeatures.stream() + .filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth) + .collect(Collectors.toList()); + + // 子节点是免授权的权限点 + Set parentNotAuthFeatureIds = notAuthFeatures.stream() + .map(e -> Optional.ofNullable(e.getParentIds()) + .map(f -> { + f.add(e.getFeatureId()); + return f; + }) + .orElseGet(() -> Sets.newHashSet(e.getFeatureId()))) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + Set notAuthFeatureIds = notAuthFeatures.stream() + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(parentNotAuthFeatureIds) && CollectionUtils.isEmpty(notAuthFeatureIds)) { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有免授权权限点")) + .build(); + } + + Set productFeatureIds = productFeatureResources.stream() + .filter(e -> Objects.equals(e.getUniCode(), uniCode)) + .map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId) + .collect(Collectors.toSet()); + + + + if (!Sets.intersection(notAuthFeatureIds, productFeatureIds).isEmpty()) { + return UniCodeCheckResult.builder() + .authPermission(true) + .reasons(Lists.newArrayList("权限点是免授权")) + .build(); + } else if (!Sets.intersection(parentNotAuthFeatureIds, productFeatureIds).isEmpty()) { + return UniCodeCheckResult.builder() + .authPermission(true) + .reasons(Lists.newArrayList("权限点的子节点是免授权")) + .build(); + } else { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("权限点不是免授权")) + .build(); + } + } + private List resolveFeatureCode(CheckPermissionParam checkPermissionParam, List productPermissions, Map> rolePermissions, @@ -1037,6 +1223,68 @@ public class PrivateController { .collect(Collectors.toList()); } + private List resolveUniCode(CheckFeatureResourceParam checkFeatureResourceParam, + List productFeatureSources, + Map> roleFeatureResources, + List roles, + List allFeatures) { + Map> productFeatureResourceMap = productFeatureSources.stream() + .map(WorkspaceProductService.ProductFeatureSource::getFeatureResources) + .flatMap(Collection::stream) + .collect(Collectors.groupingBy(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getUniCode)); + List adminRoles = roles.stream() + .filter(e -> RoleTypeEnum.isAdmin(e.getRoleType())) + .collect(Collectors.toList()); + + List normalRoles = roles.stream() + .filter(e -> !RoleTypeEnum.isAdmin(e.getRoleType())) + .collect(Collectors.toList()); + + return checkFeatureResourceParam.getUniCodes().stream() + .map(uniCode -> { + List featureResources = productFeatureResourceMap.get(uniCode); + if (CollectionUtils.isEmpty(featureResources)) { + return UniCodeCheckResult.builder() + .uniCode(uniCode) + .authPermission(false) + .reasons(Lists.newArrayList("项目没有配置产品及权限")) + .build(); + } + + if (CollectionUtils.isEmpty(roles)) { + return UniCodeCheckResult.builder() + .uniCode(uniCode) + .authPermission(false) + .reasons(Lists.newArrayList("用户在项目里没有任何角色")) + .build(); + } + + UniCodeCheckResult adminRoleCheckResult = resolveAdminRoleFeature(adminRoles, featureResources); + + UniCodeCheckResult normalRoleCheckResult = resolveNormalRoleFeature(normalRoles, featureResources, roleFeatureResources, uniCode); + + UniCodeCheckResult notAuthCheckResult = resolveNotAuthFeature(featureResources, uniCode, allFeatures); + + Boolean authPermission = BooleanUtils.isTrue(adminRoleCheckResult.getAuthPermission()) + || BooleanUtils.isTrue(normalRoleCheckResult.getAuthPermission()) + || BooleanUtils.isTrue(notAuthCheckResult.getAuthPermission()); + + List adminRoleReasons = adminRoleCheckResult.getReasons(); + List normalRoleReasons = normalRoleCheckResult.getReasons(); + List notAuthReasons = notAuthCheckResult.getReasons(); + + adminRoleReasons.addAll(normalRoleReasons); + adminRoleReasons.addAll(notAuthReasons); + + return UniCodeCheckResult.builder() + .uniCode(uniCode) + .authPermission(authPermission) + .reasons(adminRoleReasons) + .build(); + }) + .collect(Collectors.toList()); + } + private Map> listRolePermission(List roles) { if (CollectionUtils.isEmpty(roles)) { @@ -1049,15 +1297,23 @@ public class PrivateController { return rolePermissionCacheService.list(listRolePermissionParam); } - private List listProduct(List productPermissions) { + private Map> listRoleFeatureResource(List roles) { - if (CollectionUtils.isEmpty(productPermissions)) { - return Collections.emptyList(); + if (CollectionUtils.isEmpty(roles)) { + return Collections.emptyMap(); } - List productIds = productPermissions.stream() - .map(WorkspaceProductService.ProductPermission::getProductId) - .collect(Collectors.toList()); + RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRolePermissionParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder() + .roleIds(roles.stream().map(Role::getRoleId).collect(Collectors.toSet())) + .build(); + return roleSaasFeatureResourceCacheService.list(listRolePermissionParam); + } + + private List listProduct(List productIds) { + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyList(); + } return productModuleDao.listByIds(productIds).stream() .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) @@ -1079,16 +1335,18 @@ public class PrivateController { .collect(Collectors.toList()); } - private List listRole(CheckPermissionParam request) { - ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() - .personId(request.getPersonId()) - .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() - .workspaceId(request.getWorkspaceId()) - .ouId(request.getOuId()) - .build())) - .needRole(true) + private List listWorkspaceProductFeatureResource(CheckFeatureResourceParam request) { + WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam listWorkspaceProductFeatureSourceCacheParam = WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam + .builder() + .workspaceIds(Sets.newHashSet(request.getWorkspaceId())) .build(); + return workspaceProductService.listWorkspaceProductFeatureResourceCached(listWorkspaceProductFeatureSourceCacheParam).stream() + .map(WorkspaceProductService.WorkspaceProductFeatureSource::getProductFeatureSources) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + private List listRole(ListRoleUserRelationParam listRoleUserRelationParam) { return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null) .collect(Collectors.toList()) @@ -1124,6 +1382,28 @@ public class PrivateController { private String terminal; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CheckFeatureResourceParam { + + @NotNull(message = "ouId不能为空") + private Long ouId; + + @NotNull(message = "workspaceId不能为空") + private Long workspaceId; + + @NotEmpty(message = "uniCodes不能为空") + private Set uniCodes; + + @NotNull(message = "personId不能为空") + private Long personId; + + @NotBlank(message = "terminal不能为空") + private String terminal; + } + @Data @Builder @NoArgsConstructor @@ -1137,6 +1417,19 @@ public class PrivateController { private List featureCodeCheckResults; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CheckFeatureResourceDTO { + + private List products; + + private List roles; + + private List uniCodeCheckResults; + } + @Data @Builder @NoArgsConstructor @@ -1175,6 +1468,18 @@ public class PrivateController { private Boolean authPermission; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class UniCodeCheckResult { + private String uniCode; + + private List reasons; + + private Boolean authPermission; + } + @Data @Builder @NoArgsConstructor