Merge remote-tracking branch 'origin/feature/REQ-2545' into feature/REQ-2545

This commit is contained in:
李昆鹏 2024-06-28 09:46:42 +08:00
commit 65310daadb
19 changed files with 770 additions and 156 deletions

View File

@ -1,12 +1,13 @@
package cn.axzo.tyr.client.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.ResourceSyncReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDetailResp;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -44,7 +45,7 @@ public interface FeatureResourceApi {
/** 删除菜单/页面/组件 **/
@PostMapping("/api/featureResource/delete")
ApiResult<Void> deleteFeatureResource(@RequestParam Long featureId, @RequestParam Long operatorId);
ApiResult<Void> deleteFeatureResource(@Validated @RequestParam DeleteFeatureResourceReq req);
/** 重排序菜单/页面/组件 **/

View File

@ -0,0 +1,21 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeleteFeatureResourceReq {
@NotNull(message = "featureId不能为空")
private Long featureId;
@NotNull(message = "operatorId不能为空")
private Long operatorId;
}

View File

@ -65,6 +65,12 @@ public class IdentityAuthReq {
@Builder.Default
private boolean useCache = true;
/**
* 权限点类型0saas_feature,1:saas_feature_resource
* 为了兼容第三方调用查询用户的权限点会把新旧权限点都查询出来灰度端历史版本由使用方传入版本
*/
private Integer type;
public IdentityAuthRes toEmpty() {
IdentityAuthRes result = new IdentityAuthRes();
result.setIdentity(this.getIdentityId());

View File

@ -0,0 +1,33 @@
package cn.axzo.tyr.client.model.req;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.page.IPageReq;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageElementFeatureResourceRelationReq implements IPageReq {
@CriteriaField(ignore = true)
Integer page;
@CriteriaField(ignore = true)
Integer pageSize;
/**
* 排序使用示例createTime__DESC
*/
@CriteriaField(ignore = true)
List<String> sort;
@CriteriaField(field = "featureResourceUniCode", operator = Operator.IN)
private List<String> featureResourceUniCodes;
}

View File

@ -53,6 +53,16 @@ public class PageSaasFeatureResourceReq implements IPageReq {
@CriteriaField(field = "featureType", operator = Operator.IN)
private List<Integer> featureResourceTypes;
@CriteriaField(field = "path", operator = Operator.SW)
private String path;
/**
* CMS端saas_feature_resource.feature_codes已经废弃后续其他端也会这样迁移
* 新的存在saas_page_element_feature_resource_relation
*/
@CriteriaField(ignore = true)
private Boolean needFeatureCodes;
public PageResp toEmpty() {
return PageResp.builder()
.current(this.getPage())

View File

@ -0,0 +1,146 @@
package cn.axzo.tyr.client.model.res;
import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.Set;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SaasFeatureResourceResp {
private Long id;
private Date createAt;
private Date updateAt;
/**
* 资源编码-权限码
*/
private Set<String> featureCodes;
/**
* 资源名称
*/
private String featureName;
/**
* 资源类型1-菜单 2-页面 3-应用入口 4-组件;5-root节点
*/
private Integer featureType;
/**
* 资源所属端
*/
private String terminal;
/**
* 组件细分类型 1-跳转子页面 2-跳转公共组件 3-弹出窗口 4-下拉项 5-操作按钮 6-数据卡片 7-站外跳转
*/
private Integer componentType;
/**
* 上级资源ID
*/
private Long parentId;
/**
* 资源ID层级路径 逗号分隔
*/
private String path;
/**
* 展示顺序
*/
private Integer displayOrder;
/**
* 资源状态 0-隐藏 1-展示
*/
private Integer status;
/**
* 资源图标
*/
private String icon;
/**
* 跳转类型 1-站内跳转 2-站外跳转
*/
private Integer redirectType;
/**
* 资源跳转URI
*/
private String linkUrl;
/**
* 路由类型1-PC 2-小程序 3-原生
*/
private Integer linkType;
/**
* APP适配参数
*/
private String linkExt;
/**
* 小程序id
*/
private Integer appItemId;
/**
* 资源同步版本
*/
private Integer syncVersion;
/**
* 扩展字段
*/
@TableField(value = "extra", typeHandler = FastjsonTypeHandler.class)
private FeatureResourceExtraDO extra;
/**
* 授权类型0-全部角色 1-指定角色
*/
private Integer authType;
/**
* 子级鉴权类型 0-不鉴权1-鉴权
*/
private Integer subAuthType;
/**
* 创建人
*/
private Long createBy;
/**
* 更新人
*/
private Long updateBy;
/**
* 应用范围(租户类型)1:企业工作台 2;项目工作台
*/
private Long workspaceType;
/**
* 最低版本序列,主要支持版本灰度策略
*/
private Integer version;
/**
* 唯一编码用于pre环境菜单同步
*/
private String uniCode;
}

View File

@ -11,7 +11,8 @@ public enum BizResultCode implements IResultCode {
CANT_DELETE_ROLE_GROUP("100001", "不能删除角色分组,当前角色分组下有子角色分组"),
ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"),
REDIS_ROLE_NOT_NULL("100003", "角色id不能为空"),
REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空");
REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空"),
FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在");
private String errorCode;
private String errorMessage;

View File

@ -1,12 +1,11 @@
package cn.axzo.tyr.server.controller.permission;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.feign.FeatureResourceApi;
import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.ResourceSyncReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDetailResp;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.server.service.FeatureResourceSyncService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
@ -58,11 +57,10 @@ public class FeatureResourceController implements FeatureResourceApi {
}
@Override
public ApiResult<Void> deleteFeatureResource(Long featureId, Long operatorId) {
throw new ServiceException("暂时不支持删除权限点");
// log.info("deleteFeatureResource featureId : {}, operatorId : {}", featureId, operatorId);
// featureResourceService.deleteMenuFeature(featureId, operatorId);
// return ApiResult.ok();
public ApiResult<Void> deleteFeatureResource(DeleteFeatureResourceReq req) {
log.info("deleteFeatureResource req : {}", req);
featureResourceService.deleteFeatureResource(req);
return ApiResult.ok();
}
@Override

View File

@ -35,7 +35,6 @@ import cn.axzo.tyr.client.model.vo.SaasRoleVO;
import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO;
import cn.axzo.tyr.server.model.PermissionCacheKey;
import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao;
import cn.axzo.tyr.server.repository.dao.SaasRoleUserRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasRole;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
import cn.axzo.tyr.server.service.PermissionCacheService;
@ -52,8 +51,6 @@ import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
@ -83,8 +80,6 @@ public class SaasRoleController implements TyrSaasRoleApi {
@Autowired
PermissionCacheService permissionCacheService;
@Autowired
private SaasRoleUserRelationDao saasRoleUserRelationDao;
@Autowired
private SaasCommonDictService saasCommonDictService;
@Autowired
private SaasRoleGroupService saasRoleGroupService;
@ -219,7 +214,9 @@ public class SaasRoleController implements TyrSaasRoleApi {
// 因为根节点在roleGroup里面没有都是workspaceTypeCode描述是放在字典表里
List<CommonDictResp> commonDicts = listRootRole(req);
if (CollectionUtils.isEmpty(commonDicts)) {
return ApiListResult.ok();
}
List<RoleTreeRes> roots = commonDicts.stream()
.map(e -> RoleTreeRes.builder()
@ -453,18 +450,32 @@ public class SaasRoleController implements TyrSaasRoleApi {
}
private List<CommonDictResp> listRootRole(TreeRoleReq req) {
CommonDictQueryReq commonDictQueryReq = CommonDictQueryReq.builder()
.codes(StringUtils.isBlank(req.getWorkspaceTypeCode()) ? null : Lists.newArrayList(req.getWorkspaceTypeCode()))
.scope("role")
.build();
List<String> workspaceTypeCodes = StringUtils.isNotBlank(req.getWorkspaceTypeCode()) ? Lists.newArrayList(req.getWorkspaceTypeCode())
: Lists.newArrayList();
if (StringUtils.isNotBlank(req.getTerminal())) {
List<String> workspaceTypeCodes = TERMINAL_WORKSPACE_CODES.get(req.getTerminal());
if (CollectionUtils.isEmpty(workspaceTypeCodes)) {
List<String> terminalWorkspaceTypeCodes = TERMINAL_WORKSPACE_CODES.get(req.getTerminal());
if (CollectionUtils.isEmpty(terminalWorkspaceTypeCodes)) {
return Collections.emptyList();
}
commonDictQueryReq.setCodes(workspaceTypeCodes);
if (StringUtils.isBlank(req.getWorkspaceTypeCode())) {
workspaceTypeCodes = terminalWorkspaceTypeCodes;
} else {
workspaceTypeCodes = terminalWorkspaceTypeCodes.stream()
.filter(e -> Objects.equals(e, req.getWorkspaceTypeCode()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(workspaceTypeCodes)) {
return Collections.emptyList();
}
}
}
CommonDictQueryReq commonDictQueryReq = CommonDictQueryReq.builder()
.codes(workspaceTypeCodes)
.scope("role")
.build();
return saasCommonDictService.query(commonDictQueryReq);
}
}

View File

@ -1,10 +1,12 @@
package cn.axzo.tyr.server.service;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
import cn.axzo.tyr.server.model.ResourcePermission;
import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
@ -51,7 +53,10 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
List<SaasFeatureResource> list(PageSaasFeatureResourceReq param);
List<SaasFeatureResourceResp> list(PageSaasFeatureResourceReq param);
PageResp<SaasFeatureResourceResp> page(PageSaasFeatureResourceReq param);
void deleteFeatureResource(DeleteFeatureResourceReq param);
PageResp<SaasFeatureResource> page(PageSaasFeatureResourceReq param);
}

View File

@ -0,0 +1,15 @@
package cn.axzo.tyr.server.service;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface SaasPageElementFeatureResourceRelationService extends IService<SaasPageElementFeatureResourceRelation> {
List<SaasPageElementFeatureResourceRelation> list(PageElementFeatureResourceRelationReq param);
PageResp<SaasPageElementFeatureResourceRelation> page(PageElementFeatureResourceRelationReq param);
}

View File

@ -18,6 +18,8 @@ public interface SaasPgroupPermissionRelationService extends IService<SaasPgroup
List<SaasPgroupPermissionRelation> list(PagePgroupPermissionRelationReq param);
void delete(DeleteParam param);
@Data
@Builder
@NoArgsConstructor
@ -40,4 +42,12 @@ public interface SaasPgroupPermissionRelationService extends IService<SaasPgroup
*/
private Integer type;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class DeleteParam {
private List<Long> ids;
}
}

View File

@ -29,6 +29,7 @@ import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
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;
@ -44,7 +45,6 @@ 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;
@ -63,7 +63,6 @@ import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
@ -283,8 +282,9 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
return Collections.emptyList();
}
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder()
List<SaasFeatureResourceResp> saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder()
.ids(Lists.newArrayList(featureIds))
.needFeatureCodes(true)
.terminal(req.getTerminal())
.sort(Lists.newArrayList("displayOrder__ASC"))
.build());
@ -293,42 +293,19 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
return Collections.emptyList();
}
Map<String, Set<String>> featureCodes = listFeatureCodes(saasFeatureResources, req);
List<TreePermissionResp> treePermissionResps = saasFeatureResources.stream()
.map(e -> TreePermissionResp.builder()
.featureId(e.getId())
.featureName(e.getFeatureName())
.featureType(e.getFeatureType())
.redirectType(e.getRedirectType())
.linkUrl(e.getLinkUrl())
.icon(e.getIcon())
.parentId(e.getParentId())
.status(e.getStatus())
.uniCode(e.getUniCode())
.featureCodes(featureCodes.get(e.getUniCode()))
.build())
.map(e -> {
TreePermissionResp treePermissionResp = TreePermissionResp.builder().build();
BeanUtils.copyProperties(e, treePermissionResp);
treePermissionResp.setFeatureId(e.getId());
return treePermissionResp;
})
.collect(Collectors.toList());
// 组装导航树
// 过滤掉隐藏的节点因为存在某些节点被隐藏需要把这些节点和子节点给过滤掉
return TreeUtil.buildTree(treePermissionResps, (Function<TreePermissionResp, Boolean>) e -> Objects.equals(DISPLAY_STATUS, e.getStatus()));
}
private Map<String, Set<String>> listFeatureCodes(List<SaasFeatureResource> saasFeatureResources,
TreePermissionReq req) {
if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(req.isNeedFeatureCodes())) {
return Collections.emptyMap();
}
List<String> uniCodes = saasFeatureResources.stream()
.map(SaasFeatureResource::getUniCode)
.collect(Collectors.toList());
return saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(uniCodes, req.getTerminal()).stream()
.collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode,
Collectors.mapping(SaasPageElementFeatureResourceRelation::getPageElementCode, Collectors.toSet())));
}
private List<ProductFeatureRelationVO> getProductFeatureRelationByWorkspace(Set<Long> workspaceIds) {
List<ServicePkgDetailRes> servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds),
"查询租户的产品", workspaceIds).getData();
@ -573,6 +550,42 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
return Collections.emptySet();
}
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds);
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts = listWorkspaceProducts(treePermissionReq);
//免授权
List<Long> authFreeFeatureIds = listNotAuthFeatures(treePermissionReq);
//取交集确定权限
return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds);
}
private List<Long> listNotAuthFeatures(TreePermissionReq treePermissionReq) {
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.terminal(treePermissionReq.getTerminal())
.authType(FeatureResourceAuthType.ALL_ROLE.getCode())
.build();
return featureResourceService.list(pageSaasFeatureResourceReq).stream()
.map(SaasFeatureResourceResp::getId)
.collect(Collectors.toList());
}
private List<WorkspaceProductService.WorkspaceProduct> listWorkspaceProducts(TreePermissionReq treePermissionReq) {
//查询租户产品权限点
Set<Long> 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();
return workspaceProductService.listWorkspaceProduct(workspaceProductParam);
}
private List<SaasRoleUserV2DTO> listUserPermission(TreePermissionReq treePermissionReq, List<Long> featureIds) {
List<ListRoleUserRelationParam.WorkspaceOuPair> workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream()
.map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder()
.workspaceId(e.getWorkspaceId())
@ -590,36 +603,9 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
.terminal(treePermissionReq.getTerminal())
.featureIds(featureIds)
.build();
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream()
return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream()
.filter(e -> e.getSaasRole() != null && CollectionUtils.isNotEmpty(e.getSaasRole().getPermissionRelations()))
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(saasRoleUserV2DTOS)) {
log.warn("no user role relation found");
return Collections.emptySet();
}
//查询租户产品权限点
Set<Long> workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream()
.map(WorkspaceOUPair::getWorkspaceId)
.collect(Collectors.toSet());
WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder()
.terminal(treePermissionReq.getTerminal())
.workspaceIds(workspaceIds)
.featureResourceTypes(treePermissionReq.getFeatureResourceTypes())
.build();
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam);
//免授权
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.terminal(treePermissionReq.getTerminal())
.authType(FeatureResourceAuthType.ALL_ROLE.getCode())
.build();
List<Long> authFreeFeatureIds = featureResourceService.list(pageSaasFeatureResourceReq).stream()
.map(SaasFeatureResource::getId)
.collect(Collectors.toList());
//取交集确定权限
return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds);
}
private List<Long> resolveFeatureIds(TreePermissionReq treePermissionReq) {
@ -636,7 +622,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
.featureResourceTypes(featureTypes)
.build();
return featureResourceService.list(pageSaasFeatureResourceReq).stream()
.map(SaasFeatureResource::getId)
.map(SaasFeatureResourceResp::getId)
.collect(Collectors.toList());
}

View File

@ -1,7 +1,6 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.thrones.client.saas.ServicePkgClient;
@ -42,7 +41,6 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData;
/**
@ -136,17 +134,18 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation
return ApiResult.ok(Collections.emptyList());
}
List<SaasProductModuleFeatureRelation> list = saasProductModuleFeatureRelationDao.lambdaQuery()
.select(SaasProductModuleFeatureRelation::getFeatureId
,SaasProductModuleFeatureRelation::getProductModuleId
,SaasProductModuleFeatureRelation::getDictCode
,SaasProductModuleFeatureRelation::getDictCodeId
, BaseEntity::getId)
.select(SaasProductModuleFeatureRelation::getFeatureId,
SaasProductModuleFeatureRelation::getProductModuleId,
SaasProductModuleFeatureRelation::getDictCode,
SaasProductModuleFeatureRelation::getDictCodeId,
BaseEntity::getId,
SaasProductModuleFeatureRelation::getType)
.in(SaasProductModuleFeatureRelation::getProductModuleId, productIds)
.list();
return ApiResult.ok(BeanMapper.copyList(list, ProductFeatureRelationVO.class));
}
@Override
public Map<Long, List<ProductFeatureRelationVO>> getByWorkspace(Set<Long> workspaceId) {
StopWatch stopWatch = StopWatch.create(" get product by workspace");
@ -217,19 +216,13 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation
.eq(Objects.nonNull(condition.getWorkspaceJoinType()),
SaasProductModuleFeatureRelation::getDictCode, condition.getWorkspaceJoinType())
.in(CollectionUtil.isNotEmpty(condition.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, condition.getFeatureIds())
.eq(Objects.nonNull(condition.getType()), SaasProductModuleFeatureRelation::getType, condition.getType());
.eq(Objects.nonNull(condition.getType()), SaasProductModuleFeatureRelation::getType, condition.getType())
.eq(StringUtils.hasLength(condition.getTerminal()), SaasProductModuleFeatureRelation::getTerminal, condition.getTerminal());
if (!CollectionUtils.isEmpty(condition.getFeatureResourceTypes())) {
wrapper.in(SaasProductModuleFeatureRelation::getFeatureType, Lists.transform(condition.getFeatureResourceTypes(), FeatureResourceType::getCode));
}
// 目前只有新版本的CMS端产品配置时才冗余了terminal
if (Objects.equals(NEW_FEATURE, condition.getType()) && StringUtils.hasLength(condition.getTerminal())) {
TerminalInfo terminalInfo = new TerminalInfo(condition.getTerminal());
if (terminalInfo.isCMS()) {
wrapper.eq(SaasProductModuleFeatureRelation::getTerminal, condition.getTerminal());
}
}
return this.saasProductModuleFeatureRelationDao.list(wrapper);
}

View File

@ -30,8 +30,7 @@ public class SaasCommonDictServiceImpl implements SaasCommonDictService {
private final SaasCommonDictDao commonDictDao;
@Override
public List<CommonDictResp>
query(CommonDictQueryReq req) {
public List<CommonDictResp> query(CommonDictQueryReq req) {
List<SaasCommonDict> list = commonDictDao.lambdaQuery()
.eq(Objects.nonNull(req.getScope()), SaasCommonDict::getScope, req.getScope())

View File

@ -1,24 +1,30 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.basics.common.util.StopWatchUtil;
import cn.axzo.basics.common.util.TreeUtil;
import cn.axzo.foundation.dao.support.converter.PageConverter;
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.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType;
import cn.axzo.tyr.client.common.enums.FeatureResourceStatus;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq;
import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
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.res.FeatureResourceDTO;
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.model.ResourcePermission;
import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
@ -26,9 +32,13 @@ import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService;
import cn.axzo.tyr.server.service.SaasPageElementService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
import cn.azxo.framework.common.utils.StringUtils;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
@ -36,9 +46,12 @@ import cn.hutool.core.util.ObjectUtil;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -46,12 +59,14 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND;
import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE;
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
/**
* 功能资源服务实现
@ -72,6 +87,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
private final SaasFeatureResourceCacheService saasFeatureResourceCacheService;
private final SaasPageElementService saasPageElementService;
private final SaasPgroupPermissionRelationService saasPgroupPermissionRelationService;
private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService;
@Override
public List<SaasFeatureResource> listNavByIds(List<Long> featureIds, List<Integer> featureTypes) {
@ -477,7 +494,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
}
@Override
public List<SaasFeatureResource> list(PageSaasFeatureResourceReq param) {
public List<SaasFeatureResourceResp> list(PageSaasFeatureResourceReq param) {
return PageConverter.drainAll(pageNumber -> {
param.setPage(pageNumber);
param.setPageSize(500);
@ -486,7 +503,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
}
@Override
public PageResp<SaasFeatureResource> page(PageSaasFeatureResourceReq param) {
public PageResp<SaasFeatureResourceResp> page(PageSaasFeatureResourceReq param) {
String parentPath = resolveParentPath(param);
if (Objects.nonNull(param.getParentId()) && StringUtils.isBlank(parentPath)) {
@ -499,7 +516,36 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
IPage<SaasFeatureResource> page = this.page(PageConverter.toMybatis(param, SaasFeatureResource.class), wrapper);
return PageConverter.toResp(page, Function.identity());
Map<String, Set<String>> uniCodeFeatureCodeMap = listFeatureCodes(param, page.getRecords());
return PageConverter.toResp(page, e -> from(e, uniCodeFeatureCodeMap));
}
private SaasFeatureResourceResp from(SaasFeatureResource featureResource,
Map<String, Set<String>> uniCodeFeatureCodeMap) {
SaasFeatureResourceResp saasFeatureResourceResp = SaasFeatureResourceResp.builder().build();
BeanUtils.copyProperties(featureResource, saasFeatureResourceResp);
saasFeatureResourceResp.setFeatureCodes(uniCodeFeatureCodeMap.get(featureResource.getUniCode()));
return saasFeatureResourceResp;
}
private Map<String, Set<String>> listFeatureCodes(PageSaasFeatureResourceReq param,
List<SaasFeatureResource> saasFeatureResources) {
if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(param.getNeedFeatureCodes())) {
return Collections.emptyMap();
}
List<String> uniCodes = Lists.transform(saasFeatureResources, SaasFeatureResource::getUniCode);
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
.featureResourceUniCodes(uniCodes)
.build();
return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq)
.stream()
.collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode,
Collectors.mapping(SaasPageElementFeatureResourceRelation::getPageElementCode, Collectors.toSet())));
}
private String resolveParentPath(PageSaasFeatureResourceReq param) {
@ -530,4 +576,47 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
.name(saasPageElement.getName())
.build());
}
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true)
public void deleteFeatureResource(DeleteFeatureResourceReq param) {
SaasFeatureResource featureResource = this.getById(param.getFeatureId());
Axssert.checkNonNull(featureResource, FEATURE_RESOURCE_NOT_FOUND);
List<SaasFeatureResourceResp> deleteFeatureResource = this.list(PageSaasFeatureResourceReq.builder()
.path(featureResource.getPath())
.build());
// 删除自己及自己的子集
this.updateBatchById(deleteFeatureResource.stream()
.map(e -> {
SaasFeatureResource saasFeatureResource = new SaasFeatureResource();
saasFeatureResource.setId(e.getId());
saasFeatureResource.setUpdateBy(param.getOperatorId());
saasFeatureResource.setIsDelete(TableIsDeleteEnum.DELETE.value);
return saasFeatureResource;
})
.collect(Collectors.toList()));
deletePermissionRelations(deleteFeatureResource);
}
private void deletePermissionRelations(List<SaasFeatureResourceResp> deleteFeatureResource) {
PagePgroupPermissionRelationReq pagePgroupPermissionRelationReq = PagePgroupPermissionRelationReq.builder()
.featureIds(Lists.transform(deleteFeatureResource, SaasFeatureResourceResp::getId))
.type(NEW_FEATURE)
.build();
List<SaasPgroupPermissionRelation> permissionRelations = saasPgroupPermissionRelationService.list(pagePgroupPermissionRelationReq);
if (CollectionUtils.isEmpty(permissionRelations)) {
return;
}
SaasPgroupPermissionRelationService.DeleteParam deleteParam = SaasPgroupPermissionRelationService.DeleteParam.builder()
.ids(Lists.transform(permissionRelations, SaasPgroupPermissionRelation::getId))
.build();
saasPgroupPermissionRelationService.delete(deleteParam);
}
}

View File

@ -0,0 +1,43 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.foundation.dao.support.converter.PageConverter;
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper;
import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.function.Function;
@Slf4j
@Service
public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceImpl<SaasPageElementFeatureResourceRelationMapper, SaasPageElementFeatureResourceRelation>
implements SaasPageElementFeatureResourceRelationService {
@Override
public List<SaasPageElementFeatureResourceRelation> list(PageElementFeatureResourceRelationReq param) {
return PageConverter.drainAll(pageNumber -> {
param.setPage(pageNumber);
param.setPageSize(500);
return page(param);
});
}
@Override
public PageResp<SaasPageElementFeatureResourceRelation> page(PageElementFeatureResourceRelationReq param) {
QueryWrapper<SaasPageElementFeatureResourceRelation> wrapper = QueryWrapperHelper.fromBean(param, SaasPageElementFeatureResourceRelation.class);
wrapper.eq("is_delete", 0);
IPage<SaasPageElementFeatureResourceRelation> page = this.page(PageConverter.toMybatis(param, SaasPageElementFeatureResourceRelation.class), wrapper);
return PageConverter.toResp(page, Function.identity());
}
}

View File

@ -11,6 +11,7 @@ import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
import cn.axzo.tyr.server.repository.mapper.SaasPgroupPermissionRelationMapper;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -102,4 +103,13 @@ public class SaasPgroupPermissionRelationServiceImpl
return page(param);
});
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(DeleteParam param) {
if (CollectionUtil.isEmpty(param.getIds())) {
return;
}
this.removeByIds(param.getIds());
}
}

View File

@ -7,6 +7,7 @@ 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;
@ -21,6 +22,7 @@ import cn.axzo.tyr.client.model.req.ListPermissionFromFeatureReq;
import cn.axzo.tyr.client.model.req.ListPermissionFromIdentityReq;
import cn.axzo.tyr.client.model.req.ListPermissionFromRoleGroupReq;
import cn.axzo.tyr.client.model.req.OUWorkspacePair;
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;
@ -29,7 +31,6 @@ import cn.axzo.tyr.client.model.res.IdentityAuthRes;
import cn.axzo.tyr.client.model.res.ListIdentityFromPermissionResp;
import cn.axzo.tyr.client.model.res.ListPermissionFromRoleGroupResp;
import cn.axzo.tyr.client.model.res.QueryIdentityByPermissionResp;
import cn.axzo.tyr.client.model.res.SaasPermissionRes;
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;
@ -54,9 +55,11 @@ 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.RoleService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasRoleGroupService;
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
import cn.axzo.tyr.server.service.TyrSaasAuthService;
import cn.axzo.tyr.server.service.WorkspaceProductService;
import cn.axzo.tyr.server.util.KeyUtil;
import cn.axzo.tyr.server.utils.RpcExternalUtil;
import cn.azxo.framework.common.model.CommonResponse;
@ -98,6 +101,8 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE;
import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData;
import static cn.axzo.tyr.server.util.RpcInternalUtil.rpcListProcessor;
@ -128,6 +133,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
private final SaasRoleUserRelationService saasRoleUserRelationService;
private final SaasFeatureDao saasFeatureDao;
private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao;
private final WorkspaceProductService workspaceProductService;
private final SaasFeatureResourceService saasFeatureResourceService;
/**
* 通过身份查询人员权限
@ -346,6 +353,54 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
return permissionSet.containsAll(checkCodes);
}
// private IdentityAuthRes listAllNotAuthPermission(IdentityAuthReq identityAuthReq) {
// // 目前只有CMS端会同时在saas_feature和saas_feature_resource中使用
// permissionPointService.queryList(PermissionPointListQueryRequest.builder()
// .delegatedType(DelegatedType.NO_NEED.getCode())
// .build());
//
// PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
// .terminal(TerminalInfo.NT_CMS_WEB_GENERAL)
// .authType(FeatureResourceAuthType.ALL_ROLE.getCode())
// .build();
// saasFeatureResourceService.list(pageSaasFeatureResourceReq);
//
// Set<Long> workspaceIds = identityAuthReq.getWorkspaceOusPairs().stream()
// .map(IdentityAuthReq.WorkspaceOuPair::getWorkspaceId)
// .collect(Collectors.toSet());
//
// WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder()
// .workspaceIds(workspaceIds)
// .featureIds()
// .build();
// workspaceProductService.listWorkspaceProduct(workspaceProductParam);
//
//
// IdentityAuthRes result = new IdentityAuthRes();
// result.setIdentity(identityAuthReq.getIdentityId());
// result.setIdentityType(identityAuthReq.getIdentityType());
// result.setPersonId(identityAuthReq.getPersonId());
//
// List<IdentityAuthRes.WorkspacePermission> workspacePermissions = identityAuthReq.getWorkspaceOusPairs().stream()
// .map(e -> {
//
// IdentityAuthRes.WorkspacePermission workspacePermission = IdentityAuthRes.WorkspacePermission.builder()
// .workspaceId(e.getWorkspaceId())
// .ouId(e.getOuId())
// .build();
//
// IdentityAuthRes.PermissionPoint.builder()
// .featureCode(e.getCode())
// .featureId(e.getId())
// .terminal(e.getTerminal())
// .build();
// return workspacePermission;
// })
// .collect(Collectors.toList());
//
// result.setPermissions(workspacePermissions);
// return result;
// }
private IdentityAuthRes findIdentityAuth(IdentityAuthReq identityAuthReq) {
//用户角色关系
@ -357,19 +412,26 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
Set<Long> realWorkspaceId = saasRoleUserRelations.stream().map(SaasRoleUserRelation::getWorkspaceId).collect(Collectors.toSet());
//工作台对应产品 key = workspaceId
CompletableFuture<Map<Long, List<ProductFeatureRelationVO>>> workspacePermissionPointFuture = CompletableFuture
.supplyAsync(TraceSupplier.create(() -> productFeatureRelationService.getByWorkspace(realWorkspaceId)), executor);
CompletableFuture<List<WorkspaceProductService.WorkspaceProduct>> workspacePermissionPointFuture = CompletableFuture
.supplyAsync(TraceSupplier.create(() -> {
WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder()
.workspaceIds(realWorkspaceId)
.type(identityAuthReq.getType())
.build();
return workspaceProductService.listWorkspaceProduct(workspaceProductParam);
}), executor);
//查询工作台下授予的角色和权限
List<OUWRoleInfo> owRoles = listRolesWithPermission(saasRoleUserRelations, identityAuthReq);
Map<Long, List<ProductFeatureRelationVO>> workspaceProductPermissionMap = workspacePermissionPointFuture.join();
Map<Long, WorkspaceProductService.WorkspaceProduct> workspaceProductPermissionMap = workspacePermissionPointFuture.join().stream()
.collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity()));
List<CompletableFuture<IdentityAuthRes.WorkspacePermission>> futureList = new ArrayList<>();
for (OUWRoleInfo owRoleInfo : owRoles) {
// 工作台的产品权限点
List<ProductFeatureRelationVO> productFeatureRelationVOS = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId());
WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId());
//构建每个工作台的实际权限点
futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, productFeatureRelationVOS)), executor)
futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, workspaceProduct)), executor)
.exceptionally(t -> {
LogUtil.error("获取角色对应权限失败", t);
throw new ServiceException(t);
@ -387,14 +449,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
return result;
}
private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, List<ProductFeatureRelationVO> productFeatures) {
private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, WorkspaceProductService.WorkspaceProduct workspaceProduct) {
IdentityAuthRes.WorkspacePermission resultPermission = IdentityAuthRes.WorkspacePermission.builder()
.workspaceId(ouwRoleInfo.getWorkspaceId())
.ouId(ouwRoleInfo.getOuId())
.build();
if (CollectionUtil.isEmpty(productFeatures)) {
if (Objects.isNull(workspaceProduct) || CollectionUtil.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) {
log.warn("no product features found for workspace :{}", ouwRoleInfo.getWorkspaceId());
return resultPermission;
}
@ -405,25 +467,26 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
return resultPermission;
}
List<SaasProductModuleFeatureRelation> productFeatures = workspaceProduct.getSaasProductModuleFeatureRelations();
// 因为存在同时有saas_feature和saas_feature_resource的权限所以要返回type根据type解析code
//超管和管理员权限
Pair<Boolean, Set<Long>> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures);
Pair<Boolean, Set<FeatureWrapper>> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures);
//标准角和自定义角色权限
Set<Long> normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures);
Set<Long> allPermissionIds = new HashSet<>();
allPermissionIds.addAll(adminPermissions.getValue());
allPermissionIds.addAll(normalPermissions);
Set<FeatureWrapper> normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures);
Set<FeatureWrapper> allPermissions = Sets.newHashSet();
allPermissions.addAll(adminPermissions.getValue());
allPermissions.addAll(normalPermissions);
//查询权限点及父级权限点
List<SimplePermissionPointResp> allPermissionPoint = permissionPointService.listPermissionByIds(
QueryPermissionByIdsReq.builder()
.ids(allPermissionIds)
.includeParent(true)
.build());
List<SimplePermissionPointResp> allOldPermissionPoint = listOldFeatures(allPermissions);
List<IdentityAuthRes.PermissionPoint> newPermissionPoints = listNewFeatures(allPermissions);
//组装返回值
//是否超管
resultPermission.setSuperAdmin(BooleanUtil.isTrue(adminPermissions.getKey()));
//权限数据
resultPermission.getPermissionPoint().addAll(allPermissionPoint.stream()
resultPermission.getPermissionPoint().addAll(allOldPermissionPoint.stream()
.map(permissionPointTreeNode -> IdentityAuthRes.PermissionPoint.builder()
.featureCode(permissionPointTreeNode.getCode())
.featureId(permissionPointTreeNode.getId())
@ -431,14 +494,63 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
.build())
.collect(Collectors.toList()));
resultPermission.getPermissionPoint().addAll(newPermissionPoints);
return resultPermission;
}
private Set<Long> buildNormalPermission(OUWRoleInfo userRoleInfoMap, List<ProductFeatureRelationVO> productFeatures) {
private List<IdentityAuthRes.PermissionPoint> listNewFeatures(Set<FeatureWrapper> featureWrappers) {
List<Long> 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<SimplePermissionPointResp> listOldFeatures(Set<FeatureWrapper> featureWrappers) {
Set<Long> 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<FeatureWrapper> buildNormalPermission(OUWRoleInfo userRoleInfoMap, List<SaasProductModuleFeatureRelation> productFeatures) {
log.info("build permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId());
Set<Long> allMatchedProductFeatureIds = new HashSet<>();
Set<Long> allAuthPermissionIds = new HashSet<>();
Set<FeatureWrapper> allMatchedProductFeatures = new HashSet<>();
Set<FeatureWrapper> allAuthFeatures = new HashSet<>();
//聚合实际授权的权限角色权限和产品权限交集
for (SaasRoleRes role : userRoleInfoMap.getRoles()) {
//跳过超管和管理员
@ -448,40 +560,89 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
}
log.info("build permission for role:{}", role.getId());
Set<Long> rolePermissionIds = Optional.ofNullable(role.getSaasPermissions())
Set<FeatureWrapper> rolePermissions = Optional.ofNullable(role.getPermissionRelations())
.map(e -> e.stream()
.filter(Objects::nonNull)
.map(SaasPermissionRes::getId)
.map(f -> FeatureWrapper.builder()
.featureId(f.getFeatureId())
.type(f.getType())
.build())
.collect(Collectors.toSet()))
.orElseGet(Sets::newHashSet);
//角色标签类型匹配产品标签类型
Set<Long> productPermissionIds = productFeatures.stream()
Set<FeatureWrapper> productPermissions = productFeatures.stream()
.filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(role.getProductUnitType())))
.map(ProductFeatureRelationVO::getFeatureId)
.map(e -> FeatureWrapper.builder()
.featureId(e.getFeatureId())
.type(e.getType())
.build())
.collect(Collectors.toSet());
allMatchedProductFeatureIds.addAll(productPermissionIds);
allMatchedProductFeatures.addAll(productPermissions);
// 产品对应权限点 角色权限点 取交集
Collection<Long> resultHashAuthPointId = CollectionUtil.intersection(productPermissionIds, rolePermissionIds);
Collection<FeatureWrapper> resultHashAuthPointId = CollectionUtil.intersection(productPermissions, rolePermissions);
if (CollectionUtil.isNotEmpty(resultHashAuthPointId)) {
log.info("add auth permission for role:{}", role.getId());
allAuthPermissionIds.addAll(resultHashAuthPointId);
allAuthFeatures.addAll(resultHashAuthPointId);
}
}
if (CollectionUtil.isEmpty(allMatchedProductFeatureIds)) {
if (CollectionUtil.isEmpty(allMatchedProductFeatures)) {
log.info("no normal roles found");
return allAuthPermissionIds;
return allAuthFeatures;
}
// 免授权权限点统一处理
List<PermissionPointTreeNode> noNeedPermissionPoint = permissionPointService.queryList(PermissionPointListQueryRequest.builder()
.ids(new ArrayList<>(allMatchedProductFeatureIds))
.delegatedType(DelegatedType.NO_NEED.getCode())
.build());
allAuthPermissionIds.addAll(noNeedPermissionPoint.stream().map(PermissionPointTreeNode::getPermissionPointId).collect(Collectors.toSet()));
return allAuthPermissionIds;
Set<FeatureWrapper> newFeatureNoAuth = listNoAuthFeatureResources(allMatchedProductFeatures);
Set<FeatureWrapper> oldFeatureNoAuth = listNoAuthFeatures(allMatchedProductFeatures);
allAuthFeatures.addAll(newFeatureNoAuth);
allAuthFeatures.addAll(oldFeatureNoAuth);
return allAuthFeatures;
}
private Pair<Boolean, Set<Long>> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List<ProductFeatureRelationVO> productFeatures) {
private Set<FeatureWrapper> listNoAuthFeatures(Set<FeatureWrapper> featureWrappers) {
List<Long> 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<FeatureWrapper> listNoAuthFeatureResources(Set<FeatureWrapper> featureWrappers) {
List<Long> 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<Boolean, Set<FeatureWrapper>> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List<SaasProductModuleFeatureRelation> productFeatures) {
Boolean superAdmin = false;
//超管和管理员角色
List<SaasRoleRes> adminRoles = userRoleInfoMap.getRoles().stream()
@ -495,28 +656,45 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
log.info("build admin permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId());
//聚合超管和管理员的权限点 直接取角色标签和产品标签相匹配的权限点
Set<Long> permissionIds = new HashSet<>();
Set<FeatureWrapper> permissions = Sets.newHashSet();
for (SaasRoleRes adminRole : adminRoles) {
//超管查询工作台对应产品获取权限点 权限点通过单位类型过滤)
if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(adminRole.getRoleType())) {
superAdmin = true;
}
//角色标签类型匹配产品标签类型
Set<Long> buttonPermissionPointId = productFeatures.stream()
Set<FeatureWrapper> permission = productFeatures.stream()
.filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(),
String.valueOf(adminRole.getProductUnitType())))
.map(ProductFeatureRelationVO::getFeatureId)
.map(e -> FeatureWrapper.builder()
.featureId(e.getFeatureId())
.type(e.getType())
.build())
.collect(Collectors.toSet());
if (CollectionUtil.isEmpty(buttonPermissionPointId)) {
if (CollectionUtil.isEmpty(permission)) {
log.warn("empty permission for admin role:{}", adminRole.getId());
continue;
}
log.info("add all permissions for role:{}", adminRole.getId());
permissionIds.addAll(buttonPermissionPointId);
permissions.addAll(permission);
}
return Pair.of(superAdmin, permissionIds);
return Pair.of(superAdmin, permissions);
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class FeatureWrapper {
private Long featureId;
/**
* 关联类型0saas_feature,1:saas_feature_resource
*/
private Integer type;
}
private List<OUWRoleInfo> listRolesWithPermission(List<SaasRoleUserRelation> roleUserRelations, IdentityAuthReq identityAuthReq) {
@ -535,7 +713,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
//获取角色和关联权限信息
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
.roleIds(Lists.newArrayList(roleIds))
.needPermissionOld(true)
.needPermissionRelation(true)
.type(identityAuthReq.getType())
.build();
Map<Long, SaasRoleRes> saasRoleRes = roleService.list(listSaasRoleParam).stream()
.collect(Collectors.toMap(SaasRoleRes::getId, Function.identity()));
@ -727,6 +906,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
//不走缓存的情况关闭缓存开关 - 缓存临时禁用 - 请求指明不走缓存 - 角色预览操作
//请求参数去重: ou-workspace
req.distinctOUWorkspacePair();
// 因为目前只有/yoke/webApi/profile/user/v3/application接口会传入featureId使用的是app端所以这里只需要查询saas_feature的权限点
// 以为下面要根据featureId进行匹配为了解决saas_feature和saas_feature_resource有冲突的数据必须给type
if (!CollectionUtils.isEmpty(req.getFeatureId())) {
req.setType(OLD_FEATURE);
}
boolean notUseCache = !req.isUseCache()
|| CollectionUtil.isNotEmpty(req.getSpecifyRoleIds())
|| permissionCacheService.cacheDisable(
@ -1055,6 +1241,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
*/
public boolean authPermission(PermissionCheckReq req) {
// saas_feature表会被废弃所以直接查询没提供统一的查询
// 会存在灰度用户的情况接口对应的featureCode分别是saas_feature和saas_feature_resource的权限码
List<SaasFeature> saasFeatures = saasFeatureDao.lambdaQuery()
.in(SaasFeature::getFeatureCode, req.getFeatureCodes())
.eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value)
@ -1102,6 +1289,56 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
return matchNormalRole(saasRoleUserRelations, permissionProducts);
}
// private boolean authPermissionNewFeature(PermissionCheckReq req) {
// // saas_feature表会被废弃所以直接查询没提供统一的查询
// // 会存在灰度用户的情况接口对应的featureCode分别是saas_feature和saas_feature_resource的权限码
// List<SaasFeature> saasFeatures = saasFeatureResourceService.lambdaQuery()
// .in(SaasFeature::getFeatureCode, req.getFeatureCodes())
// .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value)
// .eq(StringUtils.isNotBlank(req.getTerminal()), SaasFeature::getTerminal, req.getTerminal())
// .list();
// if (CollectionUtils.isEmpty(saasFeatures)) {
// log.info("featureCode not found:{}", req.getFeatureCodes());
// return false;
// }
//
// //用户角色关系以及对应角色的权限点
// List<SaasRoleUserV2DTO> saasRoleUserRelations = listRoleUserRelations(req, saasFeatures);
// if (CollectionUtils.isEmpty(saasRoleUserRelations)) {
// return false;
// }
//
// // 查询租户开通的所有产品
// Set<Long> productIds = listProducts(req);
// if (CollectionUtils.isEmpty(productIds)) {
// log.info("product not found:{}", req.getWorkspaceId());
// return false;
// }
//
// // 查询产品开通的这些权限点的信息
// List<SaasProductModuleFeatureRelation> permissionProducts = listPermissionProduct(saasFeatures, productIds);
// if (CollectionUtils.isEmpty(productIds)) {
// log.info("permission product not found:{}", req.getWorkspaceId());
// return false;
// }
//
// // 是否有免授权的权限码且在租户开通了这个产品
// boolean matchedNoNeedAuthFeature = matchNoAuthFeature(saasFeatures, permissionProducts);
// if (BooleanUtil.isTrue(matchedNoNeedAuthFeature)) {
// log.info("has no need auth feature:{}", req.getWorkspaceId());
// return true;
// }
//
// // 是否有管理员角色且租户开通了管理员角色的单位类型对应的产品权限码
// boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, permissionProducts);
// if (BooleanUtil.isTrue(matchedAdminRole)) {
// log.info("admin role has permission:{}", req.getWorkspaceId());
// return true;
// }
//
// return matchNormalRole(saasRoleUserRelations, permissionProducts);
// }
private boolean matchNormalRole(List<SaasRoleUserV2DTO> saasRoleUserRelations,
List<SaasProductModuleFeatureRelation> permissionProducts) {
List<SaasRoleUserV2DTO> normalRoles = saasRoleUserRelations.stream()