From 3ac973964445a5846413d31a76f9e072d580b19c Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 27 Jul 2024 20:56:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:(REQ-2720)=20=E9=87=8D=E6=9E=84=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=83=E9=99=90=E5=92=8C=E6=A0=B9=E6=8D=AE=E6=9D=83?= =?UTF-8?q?=E9=99=90=E6=9F=A5=E8=AF=A2=E4=BA=BA=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/IdentityAuthReq.java | 3 + ...PageElementFeatureResourceRelationReq.java | 2 +- .../tyr/client/model/res/IdentityAuthRes.java | 7 +- .../model/roleuser/dto/SaasRoleUserV2DTO.java | 13 + .../auth/TyrSaasAuthController.java | 1 + .../tyr/server/event/inner/EventTypeEnum.java | 2 + .../SaasFeatureResourceUpsertPayload.java | 18 + .../payload/SaasFeatureUpsetPayload.java | 18 + .../mapper/SaasRoleUserRelationMapper.java | 23 + .../axzo/tyr/server/service/RoleService.java | 6 + .../service/WorkspaceProductService.java | 45 + .../impl/PermissionQueryServiceImpl.java | 88 +- .../server/service/impl/RoleServiceImpl.java | 2 +- .../impl/SaasFeatureResourceServiceImpl.java | 23 +- ...entFeatureResourceRelationServiceImpl.java | 2 +- .../service/impl/TyrSaasAuthServiceImpl.java | 997 +++++++++--------- .../impl/WorkspaceProductServiceImpl.java | 112 +- .../mapper/SaasRoleUserRelationMapper.xml | 12 + 18 files changed, 777 insertions(+), 597 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java 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 368f705f..ab35eee3 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 @@ -112,6 +112,9 @@ public class IdentityAuthReq { /** 基于角色标签查询逻辑不再用该参数 **/ private Integer workspaceJoinType; + public String buildOuWorkspaceKey() { + return this.getOuId() + "_" + this.getWorkspaceId(); + } } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java index b4f9abc2..e41f144f 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java @@ -30,7 +30,7 @@ public class PageElementFeatureResourceRelationReq implements IPageReq { List sort; @CriteriaField(field = "featureResourceUniCode", operator = Operator.IN) - private List featureResourceUniCodes; + private Set featureResourceUniCodes; @CriteriaField(field = "pageElementCode", operator = Operator.IN) private Set pageElementCodes; diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java index 07a46c40..fa3a9a2b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java @@ -58,14 +58,9 @@ public class IdentityAuthRes { private String featureCode; - // private FeatureType featureType; + private Integer featureType; private String terminal; - - /** - * 应用范围(租户类型):1:企业工作台 2;项目工作台 - */ - private Long workspaceType; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java index d031d60a..db940fbf 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java @@ -52,6 +52,19 @@ public class SaasRoleUserV2DTO { */ private Long workspaceId; + /** + * 身份Id + */ + private Long identityId; + + /** + * 身份类型 1:工人 2:从业人员 3:班组长 4:运营人员 5:政务人员 + */ + private Integer identityType; + + public String buildOuWorkspaceKey() { + return this.getOuId() + "_" + this.getWorkspaceId(); + } } @Data diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java index 0bce0cb4..a940aa93 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java @@ -85,6 +85,7 @@ public class TyrSaasAuthController implements TyrSaasAuthApi { @Override public ApiResult> listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { + return ApiResult.ok(tyrSaasAuthService.listWorkspacePermissionIdentity(req)); } @Override diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java index d7c5bdfa..b6074238 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java @@ -8,6 +8,8 @@ public enum EventTypeEnum { PRODUCT_PERMISSION_CREATED("product-permission", "product-permission-created", "产品权限添加"), ROLE_PERMISSION_CREATED("role-permission", "role-permission-created", "角色权限添加"), + SAAS_FEATURE_UPSERT("saas-feature", "saas-feature-upsert", "旧菜单树更新"), + SAAS_FEATURE_RESOURCE_UPSERT("saas-feature-resource", "saas-feature-resource-upsert", "新菜单树更新"), ; EventTypeEnum(String model, String name, String desc) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java new file mode 100644 index 00000000..6590c1cc --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java @@ -0,0 +1,18 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasFeatureResourceUpsertPayload implements Serializable { + + private Set ids; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java new file mode 100644 index 00000000..7c6349cc --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java @@ -0,0 +1,18 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasFeatureUpsetPayload implements Serializable { + + private Set ids; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java index 7547cf51..af53ee17 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java @@ -4,12 +4,35 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.Set; + @Mapper public interface SaasRoleUserRelationMapper extends BaseMapper { Page batListCleanRelation(IPage page, @Param("param") SaasRoleUserRelation cleanParam); + + /** + * 现在没有数据可以查询项目的角色 + * 通过权限点找有权限的人,需要这个接口 + * @param listRole + * @return + */ + Set listRoleIds(@Param("param") ListRole listRole); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListRole { + private Long ouId; + private Long workspaceId; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java index bf464d0d..2c6921fe 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java @@ -183,6 +183,12 @@ public interface RoleService extends IService { */ @CriteriaField(ignore = true) private String terminal; + + @CriteriaField(field = "workspaceId", operator = Operator.EQ) + private Long workspaceId; + + @CriteriaField(field = "ownerOuId", operator = Operator.EQ) + private Long ouId; } @SuperBuilder diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java index c3d4e4f1..b5f0441c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java @@ -29,6 +29,26 @@ public interface WorkspaceProductService { */ void storeWorkspaceProduct(StoreWorkspaceProductParam param); + /** + * 从缓存中查询项目的产品及产品的权限 + * @param param + * @return + */ + List listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListWorkspaceProductPermissionCacheParam { + /** + * 项目id + */ + private Set workspaceIds; + + private Set featureCodes; + } + @Data @Builder @NoArgsConstructor @@ -74,6 +94,31 @@ public interface WorkspaceProductService { private List saasProductModuleFeatureRelations; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class WorkspaceProductPermission { + + /** + * 项目id + */ + private Long workspaceId; + + private List productPermissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ProductPermission { + + private Long productId; + + private List permissions; + } + @Data @Builder @NoArgsConstructor 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 43a267bd..a508ddf8 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,9 +19,9 @@ 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.PageElementFeatureResourceRelationReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; @@ -46,14 +46,15 @@ import cn.axzo.tyr.server.model.UserIdentity; 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.dao.SaasPageElementFeatureResourceRelationDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; 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; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.WorkspaceProductService; @@ -91,7 +92,6 @@ 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,7 +117,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final SaasFeatureResourceService saasFeatureResourceService; private final SaasRoleUserRelationService saasRoleUserRelationService; private final WorkspaceProductService workspaceProductService; - private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; + private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; @Qualifier("authExecutor") @Autowired @@ -331,6 +331,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { Set defaultFeatureIds = listNotAuthFeatureIds(); allFeatureIds.addAll(featureIds); allFeatureIds.addAll(defaultFeatureIds); + + if (CollectionUtils.isEmpty(allFeatureIds)) { return Collections.emptyList(); } @@ -653,26 +655,39 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) { - List featureIds = resolveFeatureIds(treePermissionReq); + Set featureCodes = resolveFeatureCodes(treePermissionReq); - if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) { + if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureCodes)) { return Collections.emptySet(); } - List saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds); - // 用户可能没有角色 - if (CollectionUtils.isEmpty(saasRoleUserV2DTOS)) { - return Collections.emptySet(); - } + IdentityAuthReq identityAuthReq = IdentityAuthReq.builder() + .personId(treePermissionReq.getPersonId()) + .terminal(Lists.newArrayList(treePermissionReq.getTerminal())) + .workspaceOusPairs(treePermissionReq.getWorkspaceOUPairs().stream() + .map(e -> IdentityAuthReq.WorkspaceOuPair.builder() + .ouId(e.getOuId()) + .workspaceId(e.getWorkspaceId()) + .build()) + .collect(Collectors.toList())) + .featureCode(featureCodes) + .build(); - List workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds); + Set featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes()) + .map(e -> e.stream() + .map(FeatureResourceType::getCode) + .collect(Collectors.toSet())) + .orElse(null); - //免授权 - List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + return saasAuthService.findIdentityAuthMix(identityAuthReq).getPermissions().stream() + .map(IdentityAuthRes.WorkspacePermission::getPermissionPoint) + .flatMap(Collection::stream) + .filter(e -> CollectionUtils.isEmpty(featureTypes) + || featureTypes.contains(e.getFeatureType())) + .map(IdentityAuthRes.PermissionPoint::getFeatureId) + .collect(Collectors.toSet()); - //取交集确定权限 - return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); } private List listNotAuthFeatures(TreePermissionReq treePermissionReq) { @@ -685,30 +700,22 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .collect(Collectors.toList()); } - private List listWorkspaceProducts(TreePermissionReq treePermissionReq, - List featureIds) { + private List listWorkspaceProducts(TreePermissionReq treePermissionReq, + Set featureCodes) { //查询租户产品权限点 Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() .map(WorkspaceOUPair::getWorkspaceId) .collect(Collectors.toSet()); - WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() - .terminal(treePermissionReq.getTerminal()) + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam + .builder() .workspaceIds(workspaceIds) - .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) - .type(NEW_FEATURE) + .featureCodes(featureCodes) .build(); - - if (CollectionUtils.isNotEmpty(featureIds)) { - workspaceProductParam.setFeatureIdPairs(Lists.newArrayList(FeatureIdPair.builder() - .featureIds(Sets.newHashSet(featureIds)) - .type(NEW_FEATURE) - .build())); - } - return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + return workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam); } - private List listUserPermission(TreePermissionReq treePermissionReq, List featureIds) { + private List listUserPermission(TreePermissionReq treePermissionReq, Set featureCodes) { List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() .workspaceId(e.getWorkspaceId()) @@ -720,28 +727,25 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .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 List resolveFeatureIds(TreePermissionReq treePermissionReq) { + private Set resolveFeatureCodes(TreePermissionReq treePermissionReq) { if (StringUtils.isBlank(treePermissionReq.getUniCode())) { - return Collections.emptyList(); + return Collections.emptySet(); } - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .uniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) + PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() + .featureResourceUniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) .build(); - return featureResourceService.list(pageSaasFeatureResourceReq).stream() - .map(SaasFeatureResourceResp::getId) - .collect(Collectors.toList()); + return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq) + .stream() + .map(SaasPageElementFeatureResourceRelation::getPageElementCode) + .collect(Collectors.toSet()); } private Set mixFeatureIds(List saasRoleUsers, diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index e3ad93f7..39062c0c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -1131,7 +1131,7 @@ public class RoleServiceImpl extends ServiceImpl PageSaasRoleParam pageParam = PageSaasRoleParam.builder().build(); BeanUtils.copyProperties(param, pageParam); pageParam.setPage(pageNumber); - pageParam.setPageSize(500); + pageParam.setPageSize(10000); return page(pageParam); }); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 28297274..bbf6022a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -8,6 +8,7 @@ import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; import cn.axzo.foundation.exception.Axssert; import cn.axzo.foundation.page.PageResp; import cn.axzo.framework.domain.web.code.BaseCode; +import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; @@ -26,6 +27,8 @@ import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.common.util.Throws; +import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert; @@ -46,6 +49,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -64,6 +68,7 @@ import java.util.Set; import java.util.stream.Collectors; import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @@ -88,7 +93,9 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl listNavByIds(List featureIds, List featureTypes) { //按需扩展要查询的字段 @@ -252,6 +259,18 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl mqUpsertIds = Sets.newHashSet(); + mqUpsertIds.add(baseResource.getId()); + + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .ids(mqUpsertIds) + .build()) + .build(); + mqProducer.send(event); return baseResource.getId(); } @@ -552,7 +571,9 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl uniCodes = Lists.transform(saasFeatureResources, SaasFeatureResource::getUniCode); + Set uniCodes = saasFeatureResources.stream() + .map(SaasFeatureResource::getUniCode) + .collect(Collectors.toSet()); PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() .featureResourceUniCodes(uniCodes) .build(); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java index abb33ff7..c9f18b6b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java @@ -25,7 +25,7 @@ public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceIm public List list(PageElementFeatureResourceRelationReq param) { return PageConverter.drainAll(pageNumber -> { param.setPage(pageNumber); - param.setPageSize(500); + param.setPageSize(1000); return page(param); }); } 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 301eee4f..a7ea8da4 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 @@ -1,18 +1,15 @@ package cn.axzo.tyr.server.service.impl; +import cn.axzo.apollo.workspace.common.enums.TableIsDeleteEnum; import cn.axzo.basics.common.BeanMapper; -import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; -import cn.axzo.framework.domain.ServiceException; 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.enums.WorkspaceTypeCodeEnum; import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest; import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; @@ -28,7 +25,6 @@ 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; @@ -37,7 +33,6 @@ 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; @@ -46,7 +41,6 @@ import cn.axzo.tyr.server.model.FilterRoleAuth; import cn.axzo.tyr.server.model.PermissionCacheKey; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; -import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao; import cn.axzo.tyr.server.repository.entity.ProductFeatureInfo; import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; import cn.axzo.tyr.server.repository.entity.RolePermission; @@ -60,15 +54,17 @@ import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser; +import cn.axzo.tyr.server.repository.mapper.SaasRoleUserRelationMapper; import cn.axzo.tyr.server.repository.mapper.TyrSaasAuthMapper; import cn.axzo.tyr.server.service.PermissionCacheService; import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; +import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; -import cn.axzo.tyr.server.service.SaasRoleGroupRelationService; import cn.axzo.tyr.server.service.SaasRoleGroupService; import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; @@ -80,7 +76,6 @@ 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; @@ -147,14 +142,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final SaasRoleGroupService roleGroupService; private final SaasRoleUserRelationService saasRoleUserRelationService; private final SaasFeatureDao saasFeatureDao; - private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; private final WorkspaceProductService workspaceProductService; private final SaasFeatureResourceService saasFeatureResourceService; private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; private final SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; - private final SaasRoleGroupRelationService saasRoleGroupRelationService; private final FeatureCodeUtil featureCodeUtil; private final SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; + private final RolePermissionCacheService rolePermissionCacheService; + private SaasRoleUserRelationMapper saasRoleUserRelationMapper; /** * 通过身份查询人员权限 @@ -373,395 +368,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return permissionSet.containsAll(checkCodes); } - 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 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 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()) - .workspaceType(e.getWorkspaceType()) - .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()); - } - - 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 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); - } - - - @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 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; - } - @Override public boolean hasPermissionForIdentityV2(CheckIdentityPermissionReq req) { if (CollectionUtil.isEmpty(req.getCodes())) { @@ -824,79 +430,213 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .build()); } - @Override - public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { - ListIdentityFromPermissionResp result = new ListIdentityFromPermissionResp(); - result.setOuId(req.getOuId()); - result.setWorkspaceId(req.getWorkspaceId()); + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class ListPermissionUser { + private Set featureCodes; - Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); + private Long ouId; - //code查询权限点信息 - List features = permissionPointService.listNodeWithChildrenByCodes(Lists.newArrayList(newFeatureCodes), req.getTerminal()); + private Long workspaceId; - // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 - ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() - .featureCodes(newFeatureCodes) - .terminal(req.getTerminal()) + /** + * 指定端的权限 + */ + private String terminal; + } + + private List listPermissionUser(ListPermissionUser param) { + // TODO 查询免授权的featureCodes,判断featureCodes里是否有免授权的featureCodes + + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam.builder() + .workspaceIds(Sets.newHashSet(param.getWorkspaceId())) + .featureCodes(param.getFeatureCodes()) .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) + List productPermissions = workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam) .stream() - .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) - .filter(Objects::nonNull) + .map(WorkspaceProductService.WorkspaceProductPermission::getProductPermissions) + .filter(e -> !CollectionUtils.isEmpty(e)) .flatMap(Collection::stream) + .map(WorkspaceProductService.ProductPermission::getPermissions) + .filter(e -> !CollectionUtils.isEmpty(e)) + .flatMap(Collection::stream) + .filter(e -> StringUtils.isBlank(param.getTerminal()) || Objects.equals(e.getTerminal(), param.getTerminal())) .collect(Collectors.toList()); - if (CollectionUtil.isEmpty(workspaceProducts)) { + if (CollectionUtil.isEmpty(productPermissions)) { log.warn("no matched product feature in workspace"); - return result; + return Collections.emptyList(); } - List matchedUsers = getWorkspaceUser(req.getWorkspaceId(), req.getOuId(), workspaceProducts); - if (CollectionUtil.isEmpty(matchedUsers)) { + return getWorkspaceUserV2(param, productPermissions); + } + + @Override + public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { + + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); + ListPermissionUser listPermissionUser = ListPermissionUser.builder() + .featureCodes(newFeatureCodes) + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .terminal(req.getTerminal()) + .build(); + List userVOS = listPermissionUser(listPermissionUser); + + ListIdentityFromPermissionResp result = ListIdentityFromPermissionResp.builder() + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .build(); + + if (CollectionUtil.isEmpty(userVOS)) { return result; } - result.setUsers(matchedUsers); + result.setUsers(userVOS); return result; } + private List listAdminRole(ListPermissionUser req) { + //超管和管理员 + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .workspaceId(req.getWorkspaceId()) + .ouId(req.getOuId()) + .roleTypes(Lists.newArrayList(RoleTypeEnum.SUPER_ADMIN.getValue(), RoleTypeEnum.ADMIN.getValue())) + .build(); + return roleService.list(listSaasRoleParam); + } + + private Set resolvePermissionAdminRole(List adminRoles, + List productPermissions) { + Set cooperateTypes = productPermissions.stream() + .map(ProductPermissionCacheService.PermissionDTO::getCooperateType) + .collect(Collectors.toSet()); + // 有权限的管理员角色id + return adminRoles.stream() + .filter(r -> cooperateTypes.contains(String.valueOf(r.getProductUnitType()))) + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + } + + private Set resolvePermissionNormalRole(ListPermissionUser req, + List productPermissions) { + + // 因为通过权限id找对应的角色数据量巨大,所以通过找项目的角色,再找有权限的角色比较快 + Set allRoleIds = saasRoleUserRelationMapper.listRoleIds(SaasRoleUserRelationMapper.ListRole.builder() + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .build()); + + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() + .roleIds(allRoleIds) + .featureCodes(productPermissions.stream() + .map(ProductPermissionCacheService.PermissionDTO::getFeatureCode) + .collect(Collectors.toSet())) + .build(); + Map> normalRolePermissionMap = rolePermissionCacheService.list(listRolePermissionParam); + + Set normalRoleIds = normalRolePermissionMap.entrySet().stream() + .filter(e -> !CollectionUtils.isEmpty(e.getValue())) + .filter(e -> StringUtils.isBlank(req.getTerminal()) + || e.getValue().stream().anyMatch(p -> Objects.equals(p.getTerminal(), req.getTerminal()))) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + Map normalRoles = roleService.list(RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(normalRoleIds)) + .build()) + .stream() + .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); + + Map> featureCodeCooperateTypeMap = productPermissions.stream() + .collect(Collectors.groupingBy(ProductPermissionCacheService.PermissionDTO::getFeatureCode, + Collectors.mapping(ProductPermissionCacheService.PermissionDTO::getCooperateType, Collectors.toSet()))); + return normalRolePermissionMap.entrySet().stream() + .filter(e -> { + SaasRoleRes saasRoleRes = normalRoles.get(e.getKey()); + if (Objects.isNull(saasRoleRes)) { + return false; + } + + return e.getValue().stream() + .filter(f -> StringUtils.isBlank(req.getTerminal()) + || e.getValue().stream().anyMatch(p -> Objects.equals(p.getTerminal(), req.getTerminal()))) + .anyMatch(f -> { + Set productCooperateTypes = featureCodeCooperateTypeMap.get(f.getFeatureCode()); + if (CollectionUtils.isEmpty(productCooperateTypes)) { + return false; + } + return productCooperateTypes.contains(String.valueOf(saasRoleRes.getProductUnitType())); + }); + }) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + } + + private List getWorkspaceUserV2(ListPermissionUser req, + List productPermissions) { + + //超管和管理员 + List adminRoles = listAdminRole(req); + + Set adminPermissionRoleIds = resolvePermissionAdminRole(adminRoles, productPermissions); + Set normalPermissionRoleIds = resolvePermissionNormalRole(req, productPermissions); + + Set roleIds = Sets.newHashSet(); + roleIds.addAll(adminPermissionRoleIds); + roleIds.addAll(normalPermissionRoleIds); + + if (CollectionUtil.isEmpty(roleIds)) { + log.warn("no role matched product unit types"); + return Collections.emptyList(); + } + + //角色查人 + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .roleIds(Lists.newArrayList(roleIds)) + .workspaceOuPairs(Lists.newArrayList( + ListRoleUserRelationParam.WorkspaceOuPair.builder() + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .build())) + .build(); + List saasRoleUsers = saasRoleUserRelationService.listV2(listRoleUserRelationParam); + if (CollectionUtil.isEmpty(saasRoleUsers)) { + log.warn("no user role relation found. roleIds:{}, ouId:{} workspaceId:{}", roleIds, req.getOuId(), req.getWorkspaceId()); + return Collections.emptyList(); + } + + Set superAdminRoleIds = adminRoles.stream() + .filter(r -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(r.getRoleType())) + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + + //ouId -> resp : ou-identityId-identityType维度去重 + Map distinctMap = Maps.newHashMap(); + //组装去重 + // copy原代码 + for (SaasRoleUserV2DTO relation : saasRoleUsers) { + SaasRoleUserV2DTO.SaasRoleUser saasRoleUser = relation.getSaasRoleUser(); + String key = KeyUtil.buildKeyBySeparator(saasRoleUser.getOuId(), saasRoleUser.getIdentityId(), saasRoleUser.getIdentityType()); + ListIdentityFromPermissionResp.UserVO user = distinctMap.get(key); + if (user == null) { + user = ListIdentityFromPermissionResp.UserVO.builder() + .ouId(saasRoleUser.getOuId()) + .identityId(saasRoleUser.getIdentityId()) + .identityType(saasRoleUser.getIdentityType()) + .personalId(saasRoleUser.getPersonId()) + .build(); + } + if (superAdminRoleIds.contains(relation.getRoleId())) { + //超管 + user.setSuperAdmin(true); + } + distinctMap.put(key, user); + } + + return Lists.newArrayList(distinctMap.values()); + } + @Override public List batchListIdentityFromPermission(List reqList) { //异步处理 @@ -990,7 +730,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private List findIdentityPermission(IdentityAuthReq req) { - return findIdentityAuth(req).getPermissions(); + return findIdentityAuthV2(req).getPermissions(); } private List findIdentityPermissionFromCache(IdentityAuthReq req) { @@ -1170,73 +910,16 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { public List listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); - req.setFeatureCodes(Lists.newArrayList(newFeatureCodes)); - //code查询权限点信息 - List features = permissionPointService.listNodeWithChildrenByCodes(req.getFeatureCodes(), null); + Set featureCodes = Sets.newHashSet(req.getFeatureCodes()); + featureCodes.addAll(newFeatureCodes); - // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 - ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() - .featureCodes(Sets.newHashSet(req.getFeatureCodes())) + ListPermissionUser listPermissionUser = ListPermissionUser.builder() + .featureCodes(featureCodes) + .workspaceId(req.getWorkspaceId()) .build(); - List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + List users = listPermissionUser(listPermissionUser); - 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(); } @@ -1651,4 +1334,276 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .filter(e -> e.getSaasRole() != null) .collect(Collectors.toList()); } + + private List mockRoleUserRelationV2(IdentityAuthReq identityAuthReq) { + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(identityAuthReq.getSpecifyRoleIds())) + .build(); + Map saasRoles = roleService.list(listSaasRoleParam).stream() + .map(role -> SaasRoleUserV2DTO.SaasRole.builder() + .build()) + .collect(Collectors.toMap(SaasRoleUserV2DTO.SaasRole::getId, Function.identity())); + + return identityAuthReq.getWorkspaceOusPairs().stream() + .map(workspaceOuPair -> + identityAuthReq.getSpecifyRoleIds().stream() + .map(roleId -> { + SaasRoleUserV2DTO.SaasRole saasRole = saasRoles.get(roleId); + if (Objects.isNull(saasRole)) { + return null; + } + + SaasRoleUserV2DTO.SaasRoleUser saasRoleUser = SaasRoleUserV2DTO.SaasRoleUser.builder() + .ouId(workspaceOuPair.getOuId()) + .workspaceId(workspaceOuPair.getWorkspaceId()) + .identityId(identityAuthReq.getIdentityId()) + .identityType(identityAuthReq.getIdentityType().getCode()) + .build(); + return SaasRoleUserV2DTO.builder() + .roleId(roleId) + .saasRoleUser(saasRoleUser) + .saasRole(saasRole) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()) + ) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List listRoleUserRelationsV2(IdentityAuthReq identityAuthReq) { + if (CollectionUtil.isNotEmpty(identityAuthReq.getSpecifyRoleIds())) { + //指定了角色 则不需要去查用户角色关系 + log.info("mock specify roles relation"); + return mockRoleUserRelationV2(identityAuthReq); + } + + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(identityAuthReq.getPersonId()) + .identityId(identityAuthReq.getIdentityId()) + .identityType(identityAuthReq.getIdentityType()) + .workspaceOuPairs(identityAuthReq.getWorkspaceOusPairs().stream() + .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(e.getWorkspaceId()) + .ouId(e.getOuId()) + .build()) + .collect(Collectors.toList())) + .needRole(true) + .build(); + + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + .collect(Collectors.toList()); + } + + /** + * 出入参不变,方便切换, + * 基于redis缓存角色权限、产品权限进行解析 + * @param identityAuthReq + * @return + */ + private IdentityAuthRes findIdentityAuthV2(IdentityAuthReq identityAuthReq) { + + Map> workspaceProductPermissions = listWorkspaceProductPermission(identityAuthReq); + + List saasRoleUsers = listRoleUserRelationsV2(identityAuthReq); + Map> rolePermissions = listRolePermission(identityAuthReq, saasRoleUsers); + + Map> workspaceRoles = saasRoleUsers.stream() + .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), + Collectors.mapping(SaasRoleUserV2DTO::getSaasRole, Collectors.toList()))); + + List permissions = identityAuthReq.getWorkspaceOusPairs().stream() + .map(workspaceOuPair -> { + List productPermissions = Optional.ofNullable(workspaceProductPermissions.get(workspaceOuPair.getWorkspaceId())) + .map(e -> e.stream() + .map(WorkspaceProductService.ProductPermission::getPermissions) + .filter(f -> !CollectionUtils.isEmpty(f)) + .flatMap(Collection::stream) + .collect(Collectors.toList())) + .orElse(null); + + if (CollectionUtils.isEmpty(productPermissions)) { + return IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build(); + } + + List saasRoles = workspaceRoles.get(workspaceOuPair.buildOuWorkspaceKey()); + + return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions); + }) + .collect(Collectors.toList()); + + IdentityAuthRes result = new IdentityAuthRes(); + result.setIdentity(identityAuthReq.getIdentityId()); + result.setIdentityType(identityAuthReq.getIdentityType()); + result.setPersonId(identityAuthReq.getPersonId()); + result.setPermissions(permissions); + return result; + } + + private IdentityAuthRes.WorkspacePermission buildPermissionsV2(IdentityAuthReq.WorkspaceOuPair workspaceOuPair, + List productPermissions, + List saasRoles, + Map> rolePermissions) { + + IdentityAuthRes.WorkspacePermission workspacePermission = IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build(); + + //超管和管理员权限 + Set adminPermissionPoints = buildAdminPermissionV2(productPermissions, saasRoles); + Set noAuthPermissionPoints = buildNoAuthPermission(productPermissions); + Set normalPermissionPoints = buildNormalPermissionV2(productPermissions, saasRoles, rolePermissions); + + //组装返回值 + //是否超管 + boolean superAdmin = saasRoles.stream() + .anyMatch(e -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(e.getRoleType())); + workspacePermission.setSuperAdmin(superAdmin); + + Set allPermissionPoints = Sets.newHashSet(); + allPermissionPoints.addAll(adminPermissionPoints); + allPermissionPoints.addAll(noAuthPermissionPoints); + allPermissionPoints.addAll(normalPermissionPoints); + // TODO 过滤掉已经删除的权限点 + + workspacePermission.setPermissionPoint(Lists.newArrayList(allPermissionPoints)); + return workspacePermission; + } + + private Set buildAdminPermissionV2(List productPermissions, + List saasRoles) { + //超管和管理员角色 + List adminRoles = Optional.ofNullable(saasRoles) + .map(e -> e.stream() + .filter(r -> RoleTypeEnum.isAdmin(r.getRoleType())) + .collect(Collectors.toList())) + .orElse(null); + if (CollectionUtil.isEmpty(adminRoles)) { + log.info("no admin roles"); + return Collections.emptySet(); + } + + //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 + Set productUnitTypes = adminRoles.stream() + .map(SaasRoleUserV2DTO.SaasRole::getProductUnitType) + .collect(Collectors.toSet()); + + return productPermissions.stream() + .filter(e -> productUnitTypes.contains(e.getCooperateType())) + .map(e -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(e.getFeatureCode()) + .featureId(e.getFeatureId()) + .terminal(e.getTerminal()) + .featureType(e.getFeatureType()) + .build()) + .collect(Collectors.toSet()); + } + + + private Set buildNoAuthPermission(List productPermissions) { + // 旧的菜单树免授权的节点很少,所以直接查询,线上只有11个 + Set noAuthSaasFeatureCodes = permissionPointService.queryList(PermissionPointListQueryRequest.builder() + .delegatedType(DelegatedType.NO_NEED.getCode()) + .build()) + .stream() + .map(PermissionPointTreeNode::getCode) + .collect(Collectors.toSet()); + + // TODO 查询新权限树免授权的权限点 + + if (CollectionUtils.isEmpty(noAuthSaasFeatureCodes)) { + return Collections.emptySet(); + } + + return productPermissions.stream() + .filter(productPermission -> noAuthSaasFeatureCodes.contains(productPermission.getFeatureCode())) + .map(e -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(e.getFeatureCode()) + .featureId(e.getFeatureId()) + .terminal(e.getTerminal()) + .featureType(e.getFeatureType()) + .build()) + .collect(Collectors.toSet()); + } + + private Set buildNormalPermissionV2(List productPermissions, + List saasRoles, + Map> rolePermissionMap) { + + List normalRoles =Optional.ofNullable(saasRoles) + .map(e -> e.stream() + .filter(r -> !RoleTypeEnum.isAdmin(r.getRoleType())) + .collect(Collectors.toList())) + .orElse(null); + if (CollectionUtil.isEmpty(normalRoles)) { + return Collections.emptySet(); + } + + return normalRoles.stream() + .map(role -> { + + Set rolePermissionFeatureCodes = Optional.ofNullable(rolePermissionMap.get(role.getId())) + .map(e -> e.stream() + .filter(Objects::nonNull) + .map(RolePermissionCacheService.PermissionDTO::getFeatureCode) + .collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); + + if (CollectionUtils.isEmpty(rolePermissionFeatureCodes)) { + return null; + } + + return productPermissions.stream() + .filter(productPermission -> Objects.equals(productPermission.getCooperateType(), role.getProductUnitType())) + .filter(productPermission -> rolePermissionFeatureCodes.contains(productPermission.getFeatureCode())) + .map(e -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(e.getFeatureCode()) + .featureId(e.getFeatureId()) + .terminal(e.getTerminal()) + .featureType(e.getFeatureType()) + .build()) + .collect(Collectors.toSet()); + + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + private Map> listWorkspaceProductPermission(IdentityAuthReq identityAuthReq) { + Set workspaceIds = identityAuthReq.getWorkspaceOusPairs().stream() + .map(IdentityAuthReq.WorkspaceOuPair::getWorkspaceId) + .collect(Collectors.toSet()); + // 查询项目的产品权限 + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listProductPermisssion = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam.builder() + .workspaceIds(workspaceIds) + .featureCodes(identityAuthReq.getFeatureCode()) + .build(); + return workspaceProductService.listWorkspaceProductPermissionCached(listProductPermisssion).stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProductPermission::getWorkspaceId, + WorkspaceProductService.WorkspaceProductPermission::getProductPermissions)); + } + + private Map> listRolePermission(IdentityAuthReq identityAuthReq, List saasRoleUsers) { + // 因为只有非管理员才会绑定权限 + Set normalRoleIds = saasRoleUsers.stream() + .filter(e -> !RoleTypeEnum.isAdmin(e.getSaasRole().getRoleType())) + .map(SaasRoleUserV2DTO::getRoleId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(normalRoleIds)) { + return Collections.emptyMap(); + } + + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() + .roleIds(normalRoleIds) + .featureCodes(identityAuthReq.getFeatureCode()) + .build(); + return rolePermissionCacheService.list(listRolePermissionParam); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java index a2c5ac57..b8cdf79a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java @@ -10,12 +10,12 @@ import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; +import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.utils.RpcInternalUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Pair; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.common.collect.Streams; @@ -53,7 +53,10 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { @Autowired private ProductFeatureRelationService productFeatureRelationService; @Autowired - protected StringRedisTemplate redisTemplate; + private StringRedisTemplate redisTemplate; + @Autowired + private ProductPermissionCacheService productPermissionCacheService; + /** 授权缓存过期时间 **/ @Value("${workspace.product.expire:90}") @@ -136,13 +139,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { return Collections.emptyList(); } - ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder() - .workspaceIds(param.getWorkspaceIds()) - .build(); - Map> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam); - - // 存在项目没有在缓存中查询到产品的情况 - fillCacheWorkspaseProducts(param, workspaceProducts); + Map> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds()); Set productIds = workspaceProducts.values().stream() .flatMap(Collection::stream) @@ -152,19 +149,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { return Collections.emptyList(); } - // 已被删除产品过滤一层 - Set finalProductIds = productModuleDao.listByIds(productIds) - .stream() - .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) - .map(BaseEntity::getId) - .collect(Collectors.toSet()); - if (CollectionUtil.isEmpty(finalProductIds)) { - log.warn("all product is deleted for workspace :{}", param.getWorkspaceIds()); - return Collections.emptyList(); - } - ProductFeatureQuery productFeatureQuery = ProductFeatureQuery.builder() - .productIds(finalProductIds) + .productIds(productIds) .featureResourceTypes(param.getFeatureResourceTypes()) .terminal(param.getTerminal()) .type(param.getType()) @@ -238,13 +224,13 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { /** * 组装在缓存中没有查询到产品的项目 - * @param param + * @param workspaceIds * @param workspaceProducts */ - private void fillCacheWorkspaseProducts(WorkspaceProductParam param, + private void fillCacheWorkspaceProducts(Set workspaceIds, Map> workspaceProducts) { - Sets.SetView difference = Sets.difference(param.getWorkspaceIds(), workspaceProducts.keySet()); + Sets.SetView difference = Sets.difference(workspaceIds, workspaceProducts.keySet()); if (difference.isEmpty()) { return; } @@ -287,4 +273,82 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { private String getKey(Object... params) { return String.format(WORKSPACE_PRODUCT_KEY, params); } + + @Override + public List listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param) { + Map> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds()); + + Set productIds = workspaceProducts.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyList(); + } + + ProductPermissionCacheService.ListProductPermissionParam listProductPermissionParam = ProductPermissionCacheService.ListProductPermissionParam.builder() + .productIds(productIds) + .featureCodes(param.getFeatureCodes()) + .build(); + Map> productPermissionMap = productPermissionCacheService.list(listProductPermissionParam); + + return workspaceProducts.entrySet().stream() + .filter(e -> CollectionUtils.isNotEmpty(e.getValue())) + .map(e -> { + List productPermissions = e.getValue().stream() + .map(productId -> { + List permissions = productPermissionMap.get(productId); + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + return ProductPermission.builder() + .productId(productId) + .permissions(permissions) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + return WorkspaceProductPermission.builder() + .workspaceId(e.getKey()) + .productPermissions(productPermissions) + .build(); + }) + .collect(Collectors.toList()); + } + + private Map> listWorkspaceProduct(Set workspaceIds) { + if (CollectionUtils.isEmpty(workspaceIds)) { + return Collections.emptyMap(); + } + + ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder() + .workspaceIds(workspaceIds) + .build(); + Map> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam); + + // 存在项目没有在缓存中查询到产品的情况 + fillCacheWorkspaceProducts(workspaceIds, workspaceProducts); + + Set productIds = workspaceProducts.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyMap(); + } + + // 需要过滤掉已经被删除的产品 + Set finalProductIds = productModuleDao.listByIds(productIds).stream() + .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) + .map(BaseEntity::getId) + .collect(Collectors.toSet()); + workspaceProducts.entrySet().forEach(e -> { + Set effectProductIds = e.getValue().stream() + .filter(finalProductIds::contains) + .collect(Collectors.toSet()); + e.setValue(effectProductIds); + }); + + return workspaceProducts; + } } diff --git a/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml b/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml index 2792daa9..c3f2882f 100644 --- a/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml +++ b/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml @@ -19,4 +19,16 @@ AND natural_person_id = #{param.naturalPersonId} + + \ No newline at end of file