diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java index 375dd262..81e917a7 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java @@ -65,6 +65,23 @@ public class IdentityAuthReq { @Builder.Default private boolean useCache = true; + public IdentityAuthRes toEmpty() { + IdentityAuthRes result = new IdentityAuthRes(); + result.setIdentity(this.getIdentityId()); + result.setIdentityType(this.getIdentityType()); + result.setPersonId(this.getPersonId()); + + List permissions = this.getWorkspaceOusPairs().stream() + .map(workspaceOuPair -> IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build()) + .collect(Collectors.toList()); + result.setPermissions(permissions); + + return result; + } + public void distinctOUWorkspacePair() { if (CollectionUtil.isEmpty(this.workspaceOusPairs)) { return; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index 2f736f99..07bb8e99 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -19,6 +19,7 @@ import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; @@ -32,6 +33,7 @@ import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.TreePermissionResp; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; @@ -45,6 +47,7 @@ import cn.axzo.tyr.server.model.WorkspaceFeatureRelation; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import cn.axzo.tyr.server.service.PermissionQueryService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; @@ -89,7 +92,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DISPLAY_STATUS; - +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; /** * 权限查询服务实现 * @@ -117,6 +120,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; + @Qualifier("authExecutor") @Autowired private Executor executor; @@ -320,11 +324,129 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } + private List resolveFeatureIds(TreePermissionReq treePermissionReq) { + if (StringUtils.isBlank(treePermissionReq.getUniCode())) { + return Collections.emptyList(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .uniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) + .build(); + return featureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(SaasFeatureResourceResp::getId) + .collect(Collectors.toList()); + } + + private List listUserPermission(TreePermissionReq treePermissionReq, List featureIds) { + List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() + .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(e.getWorkspaceId()) + .ouId(e.getOuId()) + .build()) + .collect(Collectors.toList()); + + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(treePermissionReq.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(workspaceOuPairs)) + .needRole(true) + .needPermissionRelation(true) + .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) + .type(NEW_FEATURE) + .terminal(treePermissionReq.getTerminal()) + .featureIds(featureIds) + .build(); + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + .collect(Collectors.toList()); + } + + private Set listUserPermissionFeatureIdsFromDB(TreePermissionReq treePermissionReq) { + + List featureIds = resolveFeatureIds(treePermissionReq); + + if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + + List saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds); + + // 用户可能没有角色 + if (CollectionUtils.isEmpty(saasRoleUserV2DTOS)) { + return Collections.emptySet(); + } + + List workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds); + + //免授权 + List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + + //取交集确定权限 + return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); + } + + private Set mixFeatureIds(List saasRoleUsers, + List workspaceProducts, + List authFreeFeatureIds) { + + Map workspaceProductMap = workspaceProducts.stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); + + return saasRoleUsers.stream() + .filter(roleUser -> { + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId()); + if (workspaceProduct == null || CollectionUtils.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) { + log.warn("no workspace product feature found for id:{}", roleUser.getSaasRoleUser().getWorkspaceId()); + return false; + } + return true; + }) + .map(roleUser -> { + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId()); + + SaasRoleUserV2DTO.SaasRole saasRole = roleUser.getSaasRole(); + if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) { + return resolveAdminRole(workspaceProduct, saasRole); + } + return resolveNormalRole(workspaceProduct, saasRole, authFreeFeatureIds); + }) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + private List listWorkspaceProducts(TreePermissionReq treePermissionReq, + List featureIds) { + //查询租户产品权限点 + Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() + .map(WorkspaceOUPair::getWorkspaceId) + .collect(Collectors.toSet()); + + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .terminal(treePermissionReq.getTerminal()) + .workspaceIds(workspaceIds) + .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) + .type(NEW_FEATURE) + .build(); + + if (CollectionUtils.isNotEmpty(featureIds)) { + workspaceProductParam.setFeatureIdPairs(Lists.newArrayList(FeatureIdPair.builder() + .featureIds(Sets.newHashSet(featureIds)) + .type(NEW_FEATURE) + .build())); + } + return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + } + @Override public List treePermission(TreePermissionReq req) { Set allFeatureIds = Sets.newHashSet(); - Set featureIds = listUserPermissionFeatureIds(req); + Set featureIds; + try { + featureIds = listUserPermissionFeatureIds(req); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + featureIds = listUserPermissionFeatureIdsFromDB(req); + } Set defaultFeatureIds = listNotAuthFeatureIds(); allFeatureIds.addAll(featureIds); @@ -829,4 +951,33 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .filter(authFreeFeatureIds::contains) .collect(Collectors.toSet()); } + + private List resolveAdminRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, + SaasRoleUserV2DTO.SaasRole saasRole) { + + //超管和管理员 直接取和角色类型匹配的租户产品权限 + return workspaceProduct.getSaasProductModuleFeatureRelations().stream() + .filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString()) + || !NumberUtil.isPositiveNumber(saasRole.getProductUnitType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toList()); + } + + private List resolveNormalRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, + SaasRoleUserV2DTO.SaasRole saasRole, + List authFreeFeatureIds) { + //普通角色:角色同类型的租户产品权限已分配 且角色上已分配 + 免授权 + Set roleFeatureIds = Optional.ofNullable(saasRole.getPermissionRelations()) + .map(e -> e.stream() + .map(SaasPermissionRelationRes::getFeatureId) + .collect(Collectors.toSet())) + .orElseGet(Collections::emptySet); + + return workspaceProduct.getSaasProductModuleFeatureRelations().stream() + .filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString()) + || !NumberUtil.isPositiveNumber(saasRole.getProductUnitType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .filter(id -> roleFeatureIds.contains(id) || authFreeFeatureIds.contains(id)) + .collect(Collectors.toList()); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index ce43f82e..db6bb867 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -7,10 +7,12 @@ import cn.axzo.pokonyan.util.TraceSupplier; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes; +import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.common.enums.WorkspaceJoinType; import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.enums.IdentityType; +import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest; import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; import cn.axzo.tyr.client.model.req.CheckIdentityPermissionReq; @@ -25,6 +27,7 @@ import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.req.PermissionCheckReq; +import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; import cn.axzo.tyr.client.model.req.QuerySaasRoleReq; import cn.axzo.tyr.client.model.req.WorkspacePermissionIdentityReq; import cn.axzo.tyr.client.model.res.IdentityAuthRes; @@ -33,6 +36,7 @@ import cn.axzo.tyr.client.model.res.ListPermissionFromRoleGroupResp; import cn.axzo.tyr.client.model.res.QueryIdentityByPermissionResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO; @@ -76,6 +80,7 @@ import cn.azxo.framework.common.model.CommonResponse; import cn.azxo.framework.common.utils.LogUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.StopWatch; +import cn.hutool.core.lang.Pair; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; @@ -520,7 +525,15 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { @Override public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { + try { + return listIdentityFromPermissionResp(req); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return listIdentityFromPermissionFromDB(req); + } + } + private ListIdentityFromPermissionResp listIdentityFromPermissionResp(ListIdentityFromPermissionReq req) { Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); ListPermissionUser listPermissionUser = ListPermissionUser.builder() .featureCodes(newFeatureCodes) @@ -781,7 +794,12 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private List findIdentityPermission(IdentityAuthReq req) { - return findIdentityAuthV2(req).getPermissions(); + try { + return findIdentityAuthV2(req).getPermissions(); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return findIdentityAuth(req).getPermissions(); + } } private List findIdentityPermissionFromCache(IdentityAuthReq req) { @@ -960,32 +978,37 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { @Override public List listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { - Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); + try { + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); - Set featureCodes = Sets.newHashSet(req.getFeatureCodes()); - featureCodes.addAll(newFeatureCodes); + Set featureCodes = Sets.newHashSet(req.getFeatureCodes()); + featureCodes.addAll(newFeatureCodes); - ListPermissionUser listPermissionUser = ListPermissionUser.builder() - .featureCodes(featureCodes) - .workspaceId(req.getWorkspaceId()) - .build(); - List users = listPermissionUser(listPermissionUser); - - if (CollectionUtil.isEmpty(users)) { - return Collections.emptyList(); - } - //按ou分组返回 - List result = new ArrayList<>(); - Map> userMap = users.stream() - .collect(Collectors.groupingBy(ListIdentityFromPermissionResp.UserVO::getOuId)); - for (Map.Entry> entry : userMap.entrySet()) { - result.add(ListIdentityFromPermissionResp.builder() + ListPermissionUser listPermissionUser = ListPermissionUser.builder() + .featureCodes(featureCodes) .workspaceId(req.getWorkspaceId()) - .ouId(entry.getKey()) - .users(entry.getValue()) - .build()); + .build(); + List users = listPermissionUser(listPermissionUser); + + if (CollectionUtil.isEmpty(users)) { + return Collections.emptyList(); + } + //按ou分组返回 + List result = new ArrayList<>(); + Map> userMap = users.stream() + .collect(Collectors.groupingBy(ListIdentityFromPermissionResp.UserVO::getOuId)); + for (Map.Entry> entry : userMap.entrySet()) { + result.add(ListIdentityFromPermissionResp.builder() + .workspaceId(req.getWorkspaceId()) + .ouId(entry.getKey()) + .users(entry.getValue()) + .build()); + } + return result; + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return listWorkspacePermissionIdentityFromDB(req); } - return result; } private List listFeatureRoles(Set featureIds, Integer type) { @@ -1685,4 +1708,550 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .build(); return rolePermissionCacheService.list(listRolePermissionParam); } + + private IdentityAuthRes findIdentityAuth(IdentityAuthReq identityAuthReq) { + //用户角色关系 + List saasRoleUserRelations = listRoleUserRelations(identityAuthReq); + if (CollectionUtils.isEmpty(saasRoleUserRelations)) { + log.warn("no user role relations found"); + return identityAuthReq.toEmpty(); + } + + Set realWorkspaceId = saasRoleUserRelations.stream().map(SaasRoleUserRelation::getWorkspaceId).collect(Collectors.toSet()); + //工作台对应产品 key = workspaceId + CompletableFuture> workspacePermissionPointFuture = CompletableFuture + .supplyAsync(TraceSupplier.create(() -> { + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(realWorkspaceId) + .build(); + return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + }), executor); + //查询工作台下授予的角色和权限 + List owRoles = listRolesWithPermission(saasRoleUserRelations, identityAuthReq); + + Map workspaceProductPermissionMap = workspacePermissionPointFuture.join().stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); + + List> futureList = new ArrayList<>(); + for (OUWRoleInfo owRoleInfo : owRoles) { + // 工作台的产品权限点 + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId()); + //构建每个工作台的实际权限点 + futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, workspaceProduct)), executor) + .exceptionally(t -> { + LogUtil.error("获取角色对应权限失败", t); + throw new ServiceException(t); + })); + } + + //汇总结果 + IdentityAuthRes result = new IdentityAuthRes(); + result.setIdentity(identityAuthReq.getIdentityId()); + result.setIdentityType(identityAuthReq.getIdentityType()); + result.setPersonId(identityAuthReq.getPersonId()); + for (CompletableFuture future : futureList) { + result.getPermissions().add(future.join()); + } + return result; + } + + private List listRoleUserRelations(IdentityAuthReq identityAuthReq) { + if (CollectionUtil.isNotEmpty(identityAuthReq.getSpecifyRoleIds())) { + //指定了角色 则不需要去查用户角色关系 + log.info("mock specify roles relation"); + return mockRoleUserRelation(identityAuthReq); + } + //查询人员角色关系 + Set workspaceIds = new HashSet<>(); + Set ouIds = new HashSet<>(); + Set owKeys = new HashSet<>(); + identityAuthReq.getWorkspaceOusPairs().forEach(ow -> { + workspaceIds.add(ow.getWorkspaceId()); + ouIds.add(ow.getOuId()); + owKeys.add(KeyUtil.buildKeyBySeparator(ow.getWorkspaceId(), ow.getOuId())); + }); + List relations = roleUserService.queryByWorkspaceIdOrOu(identityAuthReq.getPersonId(), + identityAuthReq.getIdentityId(), identityAuthReq.getIdentityType(), workspaceIds, ouIds); + if (CollectionUtil.isEmpty(relations)) { + log.warn("no user role relations found"); + return relations; + } + //工作台和单位需成对查询, 对结果二次过滤 + return relations.stream() + .filter(roleUserService -> owKeys.contains( + KeyUtil.buildKeyBySeparator(roleUserService.getWorkspaceId(), roleUserService.getOuId()))) + .collect(Collectors.toList()); + } + + private List mockRoleUserRelation(IdentityAuthReq identityAuthReq) { + final List relations = new ArrayList<>(); + // mock 看做已有指定的角色 + for (IdentityAuthReq.WorkspaceOuPair ow : identityAuthReq.getWorkspaceOusPairs()) { + List mockRelations = identityAuthReq.getSpecifyRoleIds().stream().map(id -> { + SaasRoleUserRelation relation = new SaasRoleUserRelation(); + relation.setRoleId(id); + relation.setOuId(ow.getOuId()); + relation.setWorkspaceId(ow.getWorkspaceId()); + relation.setIdentityId(identityAuthReq.getIdentityId()); + relation.setIdentityType(identityAuthReq.getIdentityType().getCode()); + // 使用角色ID替代,不需要在查询一次 + relation.setId(id); + return relation; + }).collect(Collectors.toList()); + relations.addAll(mockRelations); + } + return relations; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class FeatureWrapper { + private Long featureId; + + /** + * 关联类型(0:saas_feature,1:saas_feature_resource) + */ + private Integer type; + } + + private List listRolesWithPermission(List roleUserRelations, IdentityAuthReq identityAuthReq) { + + //拼装参数 + Set roleIds = new HashSet<>(); + //按ow分组角色ID: workspaceId-ouId --> roleIds + Map> owRoleIdMap = new HashMap<>(); + for (SaasRoleUserRelation relation : roleUserRelations) { + roleIds.add(relation.getRoleId()); + String key = KeyUtil.buildKeyBySeparator(relation.getWorkspaceId(), relation.getOuId()); + Set owRoleIds = owRoleIdMap.getOrDefault(key, new HashSet<>()); + owRoleIds.add(relation.getRoleId()); + owRoleIdMap.put(key, owRoleIds); + } + //获取角色和关联权限信息 + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(roleIds)) + .needPermissionRelation(true) + .build(); + Map saasRoleRes = roleService.list(listSaasRoleParam).stream() + .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); + + //按ow组装拥有的角色 + List owRoleMap = new ArrayList<>(); + for (IdentityAuthReq.WorkspaceOuPair ow : identityAuthReq.getWorkspaceOusPairs()) { + OUWRoleInfo owRoleInfo = OUWRoleInfo.builder() + .workspaceId(ow.getWorkspaceId()) + .ouId(ow.getOuId()) + .build(); + String key = KeyUtil.buildKeyBySeparator(ow.getWorkspaceId(), ow.getOuId()); + Set owRoleIds = owRoleIdMap.get(key); + if (CollectionUtil.isEmpty(owRoleIds)) { + log.info("no roles found for ow:{}", key); + owRoleInfo.setRoles(Collections.emptySet()); + } else { + owRoleInfo.setRoles(owRoleIds.stream() + .map(saasRoleRes::get) + // 有saas_role_user_relation有记录,但是对应的saas_role不存在的情况 + .filter(Objects::nonNull) + .collect(Collectors.toSet())); + } + owRoleMap.add(owRoleInfo); + } + + return owRoleMap; + } + + private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, WorkspaceProductService.WorkspaceProduct workspaceProduct) { + + IdentityAuthRes.WorkspacePermission resultPermission = IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(ouwRoleInfo.getWorkspaceId()) + .ouId(ouwRoleInfo.getOuId()) + .build(); + + if (Objects.isNull(workspaceProduct) || CollectionUtil.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) { + log.warn("no product features found for workspace :{}", ouwRoleInfo.getWorkspaceId()); + return resultPermission; + } + + Set roles = ouwRoleInfo.getRoles(); + if (CollectionUtil.isEmpty(roles)) { + log.warn("no roles for ou:{} workspace:{}", ouwRoleInfo.getOuId(), ouwRoleInfo.getWorkspaceId()); + return resultPermission; + } + + List productFeatures = workspaceProduct.getSaasProductModuleFeatureRelations(); + // 因为存在同时有saas_feature和saas_feature_resource的权限,所以要返回type,根据type解析code + //超管和管理员权限 + Pair> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures); + //标准角和自定义角色权限 + Set normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures); + Set allPermissions = Sets.newHashSet(); + allPermissions.addAll(adminPermissions.getValue()); + allPermissions.addAll(normalPermissions); + + //查询权限点及父级权限点 + List allOldPermissionPoint = listOldFeatures(allPermissions); + + List newPermissionPoints = listNewFeatures(allPermissions); + + //组装返回值 + //是否超管 + resultPermission.setSuperAdmin(BooleanUtil.isTrue(adminPermissions.getKey())); + //权限数据 + resultPermission.getPermissionPoint().addAll(allOldPermissionPoint.stream() + .map(permissionPointTreeNode -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(permissionPointTreeNode.getCode()) + .featureId(permissionPointTreeNode.getId()) + .terminal(permissionPointTreeNode.getTerminal()) + .build()) + .collect(Collectors.toList())); + + resultPermission.getPermissionPoint().addAll(newPermissionPoints); + return resultPermission; + } + + private Pair> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { + Boolean superAdmin = false; + //超管和管理员角色 + List adminRoles = userRoleInfoMap.getRoles().stream() + .filter(r -> RoleTypeEnum.isAdmin(r.getRoleType())) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(adminRoles)) { + log.info("no admin roles"); + return Pair.of(superAdmin, Collections.emptySet()); + } + + log.info("build admin permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); + + //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 + Set permissions = Sets.newHashSet(); + for (SaasRoleRes adminRole : adminRoles) { + //超管:查询工作台对应产品,获取权限点, ( 权限点通过单位类型过滤) + if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(adminRole.getRoleType())) { + superAdmin = true; + } + //角色标签类型匹配产品标签类型 + Set permission = productFeatures.stream() + .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), + String.valueOf(adminRole.getProductUnitType()))) + .map(e -> FeatureWrapper.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .build()) + .collect(Collectors.toSet()); + + if (CollectionUtil.isEmpty(permission)) { + log.warn("empty permission for admin role:{}", adminRole.getId()); + continue; + } + log.info("add all permissions for role:{}", adminRole.getId()); + permissions.addAll(permission); + } + + return Pair.of(superAdmin, permissions); + } + + private Set buildNormalPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { + + log.info("build permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); + Set allMatchedProductFeatures = new HashSet<>(); + Set allAuthFeatures = new HashSet<>(); + + //聚合实际授权的权限:角色权限和产品权限交集 + for (SaasRoleRes role : userRoleInfoMap.getRoles()) { + //跳过超管和管理员 + if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(role.getRoleType()) + || RoleTypeEnum.ADMIN.getValue().equals(role.getRoleType())) { + continue; + } + log.info("build permission for role:{}", role.getId()); + + Set rolePermissions = Optional.ofNullable(role.getPermissionRelations()) + .map(e -> e.stream() + .filter(Objects::nonNull) + .map(f -> FeatureWrapper.builder() + .featureId(f.getFeatureId()) + .type(f.getType()) + .build()) + .collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); + //角色标签类型匹配产品标签类型 + Set productPermissions = productFeatures.stream() + .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(role.getProductUnitType()))) + .map(e -> FeatureWrapper.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .build()) + .collect(Collectors.toSet()); + allMatchedProductFeatures.addAll(productPermissions); + // 产品对应权限点 与 角色权限点 取交集 + Collection resultHashAuthPointId = CollectionUtil.intersection(productPermissions, rolePermissions); + if (CollectionUtil.isNotEmpty(resultHashAuthPointId)) { + log.info("add auth permission for role:{}", role.getId()); + allAuthFeatures.addAll(resultHashAuthPointId); + } + } + if (CollectionUtil.isEmpty(allMatchedProductFeatures)) { + log.info("no normal roles found"); + return allAuthFeatures; + } + + Set newFeatureNoAuth = listNoAuthFeatureResources(allMatchedProductFeatures); + + Set oldFeatureNoAuth = listNoAuthFeatures(allMatchedProductFeatures); + allAuthFeatures.addAll(newFeatureNoAuth); + allAuthFeatures.addAll(oldFeatureNoAuth); + return allAuthFeatures; + } + + private Set listNoAuthFeatures(Set featureWrappers) { + List featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + + return permissionPointService.queryList(PermissionPointListQueryRequest.builder() + .ids(featureIds) + .delegatedType(DelegatedType.NO_NEED.getCode()) + .build()) + .stream() + .map(e -> FeatureWrapper.builder() + .featureId(e.getPermissionPointId()) + .type(OLD_FEATURE) + .build()) + .collect(Collectors.toSet()); + } + + private Set listNoAuthFeatureResources(Set featureWrappers) { + List featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(e -> FeatureWrapper.builder() + .featureId(e.getId()) + .type(NEW_FEATURE) + .build()) + .collect(Collectors.toSet()); + } + + private List listNewFeatures(Set featureWrappers) { + List featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } + + // 因为新版本配置权限点的时候,会在选中某个权限节点时,把所有父节点也冗余到权限里,所以只需要查询权限点信息 + return saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needFeatureCodes(true) + .build()) + .stream() + .filter(e -> !CollectionUtils.isEmpty(e.getFeatureCodes())) + .map(e -> + // 兼容历史情况,根据featureCode组装数据 + e.getFeatureCodes().stream() + .map(featureCode -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(featureCode) + .featureId(e.getId()) + .terminal(e.getTerminal()) + .build()) + .collect(Collectors.toList())) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List listOldFeatures(Set featureWrappers) { + Set featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } + + return permissionPointService.listPermissionByIds( + QueryPermissionByIdsReq.builder() + .ids(featureIds) + .includeParent(true) + .build()); + } + + public ListIdentityFromPermissionResp listIdentityFromPermissionFromDB(ListIdentityFromPermissionReq req) { + ListIdentityFromPermissionResp result = new ListIdentityFromPermissionResp(); + result.setOuId(req.getOuId()); + result.setWorkspaceId(req.getWorkspaceId()); + + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); + + //code查询权限点信息 + List features = permissionPointService.listNodeWithChildrenByCodes(Lists.newArrayList(newFeatureCodes), req.getTerminal()); + + // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(newFeatureCodes) + .terminal(req.getTerminal()) + .build(); + List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + + if (CollectionUtil.isEmpty(features) && CollectionUtils.isEmpty(saasFeatureResources)) { + log.warn("no features data found for:{}", req.getFeatureCode()); + return result; + } + //是否免授权权限点 + Optional freeFeature = features.stream() + .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) + .findAny(); + + Optional freeFeatureResource = saasFeatureResources.stream() + .filter(e -> SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .findFirst(); + + if (freeFeature.isPresent() || freeFeatureResource.isPresent()) { + log.warn("free feature found : featureId:{}, featureResourceId:{}", + freeFeature.map(SaasFeature::getId).orElse(null), + freeFeatureResource.map(SaasFeatureResourceResp::getId).orElse(null)); + throw new ServiceException("不能查询免授权权限点人员"); + } + + Set featureIds = features.stream().map(SaasFeature::getId).collect(Collectors.toSet()); + Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); + + List featureIdPairs = Lists.newArrayList(); + if (!CollectionUtils.isEmpty(featureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()); + } + + if (!CollectionUtils.isEmpty(newFeatureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build()); + } + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(featureIdPairs) + .build(); + List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam) + .stream() + .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtil.isEmpty(workspaceProducts)) { + log.warn("no matched product feature in workspace"); + return result; + } + + List matchedUsers = getWorkspaceUser(req.getWorkspaceId(), req.getOuId(), workspaceProducts); + if (CollectionUtil.isEmpty(matchedUsers)) { + return result; + } + result.setUsers(matchedUsers); + return result; + } + + public List listWorkspacePermissionIdentityFromDB(WorkspacePermissionIdentityReq req) { + + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); + req.setFeatureCodes(Lists.newArrayList(newFeatureCodes)); + + //code查询权限点信息 + List features = permissionPointService.listNodeWithChildrenByCodes(req.getFeatureCodes(), null); + + // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(Sets.newHashSet(req.getFeatureCodes())) + .build(); + List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + + if (CollectionUtil.isEmpty(features) && CollectionUtils.isEmpty(saasFeatureResources)) { + log.warn("no features data found for:{}", req.getFeatureCodes()); + return Collections.emptyList(); + } + Set featureIds = features.stream().map(SaasFeature::getId).collect(Collectors.toSet()); + Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); + List featureIdPairs = Lists.newArrayList(); + + if (!CollectionUtils.isEmpty(featureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()); + } + + if (!CollectionUtils.isEmpty(newFeatureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build()); + } + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(featureIdPairs) + .build(); + List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam) + .stream() + .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtil.isEmpty(workspaceProducts)) { + log.warn("no matched feature in workspace product"); + return Collections.emptyList(); + } + + //是否免授权权限点 + Set matchedOldFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(OLD_FEATURE, e.getType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); + Optional freeFeature = features.stream() + .filter(f -> matchedOldFeatureIds.contains(f.getId())) + .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) + .findAny(); + + Set matchedNewFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(NEW_FEATURE, e.getType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); + + Optional freeFeatureResource = saasFeatureResources.stream() + .filter(f -> matchedNewFeatureIds.contains(f.getId())) + .filter(e -> SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .findFirst(); + if (freeFeature.isPresent() || freeFeatureResource.isPresent()) { + throw new ServiceException("免授权权限点调用查人接口"); + } + + //从相关角色查询用户-超管和普通角色 + List users = getWorkspaceUser(req.getWorkspaceId(), null, workspaceProducts); + if (CollectionUtil.isEmpty(users)) { + return Collections.emptyList(); + } + //按ou分组返回 + List result = new ArrayList<>(); + Map> userMap = users.stream() + .collect(Collectors.groupingBy(ListIdentityFromPermissionResp.UserVO::getOuId)); + for (Map.Entry> entry : userMap.entrySet()) { + result.add(ListIdentityFromPermissionResp.builder() + .workspaceId(req.getWorkspaceId()) + .ouId(entry.getKey()) + .users(entry.getValue()) + .build()); + } + return result; + } }