From c3506077624afcbaaa77ac7aa1dfe4f42228cd9a Mon Sep 17 00:00:00 2001 From: tjq Date: Tue, 13 Feb 2024 16:22:56 +0800 Subject: [PATCH] feat: support user related query --- .../permission/PowerJobPermissionService.java | 10 +++++++++- .../PowerJobPermissionServiceImpl.java | 15 +++++++++++++++ .../remote/repository/AppInfoRepository.java | 2 ++ .../remote/repository/UserRoleRepository.java | 2 ++ .../server/auth/service/WebAuthService.java | 4 ++++ .../auth/service/impl/WebAuthServiceImpl.java | 19 +++++++++++++++++++ .../web/ControllerExceptionHandler.java | 4 ++-- .../web/controller/AppInfoController.java | 18 ++++++++++++++++-- .../web/controller/NamespaceController.java | 14 ++++++++++++++ 9 files changed, 83 insertions(+), 5 deletions(-) diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionService.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionService.java index 0d49f9d5..382f02cc 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionService.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionService.java @@ -47,9 +47,17 @@ public interface PowerJobPermissionService { /** * 获取有相关权限的用户 - * @param roleScope 权限范围 + * @param roleScope 角色范围 * @param target 目标 * @return 角色对应的用户列表 */ Map> fetchUserWithPermissions(RoleScope roleScope, Long target); + + /** + * 获取用户有权限的目标 + * @param roleScope 角色范围 + * @param userId 用户ID + * @return result + */ + Map> fetchUserHadPermissionTargets(RoleScope roleScope, Long userId); } diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionServiceImpl.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionServiceImpl.java index 3b8495e8..e62e7853 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionServiceImpl.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/permission/PowerJobPermissionServiceImpl.java @@ -123,6 +123,21 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService return ret; } + @Override + public Map> fetchUserHadPermissionTargets(RoleScope roleScope, Long userId) { + + Map> ret = Maps.newHashMap(); + List userRoleDOList = userRoleRepository.findAllByUserIdAndScope(userId, roleScope.getV()); + + Optional.ofNullable(userRoleDOList).orElse(Collections.emptyList()).forEach(r -> { + Role role = Role.of(r.getRole()); + List targetIds = ret.computeIfAbsent(role, ignore -> Lists.newArrayList()); + targetIds.add(r.getTarget()); + }); + + return ret; + } + private boolean checkAppPermission(Long targetId, Permission requiredPermission, Multimap appId2Role, Multimap namespaceId2Role) { final Collection appRoles = appId2Role.get(targetId); diff --git a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/AppInfoRepository.java b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/AppInfoRepository.java index bfdc0f5a..684b0d56 100644 --- a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/AppInfoRepository.java +++ b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/AppInfoRepository.java @@ -32,4 +32,6 @@ public interface AppInfoRepository extends JpaRepository, JpaSp @Query(value = "select id from AppInfoDO where currentServer = :currentServer") List listAppIdByCurrentServer(@Param("currentServer")String currentServer); + List findAllByNamespaceId(Long namespaceId); + } diff --git a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserRoleRepository.java b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserRoleRepository.java index 6a630caa..fb4c69cf 100644 --- a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserRoleRepository.java +++ b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserRoleRepository.java @@ -18,4 +18,6 @@ public interface UserRoleRepository extends JpaRepository { List findAllByScopeAndTarget(Integer scope, Long target); List findAllByScopeAndTargetAndRoleAndUserId(Integer scope, Long target, Integer role, Long userId); + + List findAllByUserIdAndScope(Long userId, Integer scope); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java index 51593027..63c812f7 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java @@ -4,6 +4,8 @@ import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.RoleScope; import tech.powerjob.server.web.request.ComponentUserRoleInfo; +import java.util.Set; + /** * Web Auth 服务 * 写在 starter 包下,抽取 controller 的公共逻辑 @@ -38,4 +40,6 @@ public interface WebAuthService { * @return 是否有权限 */ boolean hasPermission(RoleScope roleScope, Long target, Permission permission); + + Set fetchMyPermissionTargets(RoleScope roleScope); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java index f53fdd6a..bdc2ac27 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java @@ -6,6 +6,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import tech.powerjob.common.serialize.JsonUtils; import tech.powerjob.server.auth.*; +import tech.powerjob.server.auth.common.AuthErrorCode; +import tech.powerjob.server.auth.common.PowerJobAuthException; import tech.powerjob.server.auth.service.WebAuthService; import tech.powerjob.server.auth.service.permission.PowerJobPermissionService; import tech.powerjob.server.web.request.ComponentUserRoleInfo; @@ -59,6 +61,23 @@ public class WebAuthServiceImpl implements WebAuthService { return powerJobPermissionService.hasPermission(powerJobUser.getId(), roleScope, target, permission); } + @Override + public Set fetchMyPermissionTargets(RoleScope roleScope) { + + PowerJobUser powerJobUser = LoginUserHolder.get(); + if (powerJobUser == null) { + throw new PowerJobAuthException(AuthErrorCode.USER_NOT_LOGIN); + } + + Map> role2TargetIds = powerJobPermissionService.fetchUserHadPermissionTargets(roleScope, powerJobUser.getId()); + + Set targetIds = Sets.newHashSet(); + role2TargetIds.values().forEach(targetIds::addAll); + + // 展示不考虑穿透权限的问题(即拥有 namespace 权限也可以看到全部的 apps) + return targetIds; + } + private void diffGrant(RoleScope roleScope, Long target, Role role, List uids, Map> originRole2Uids) { Set originUids = Sets.newHashSet(Optional.ofNullable(originRole2Uids.get(role)).orElse(Collections.emptyList())); diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/ControllerExceptionHandler.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/ControllerExceptionHandler.java index 8bfcd1b9..0c9b856f 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/ControllerExceptionHandler.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/ControllerExceptionHandler.java @@ -30,9 +30,9 @@ public class ControllerExceptionHandler { // 不是所有异常都需要打印完整堆栈,后续可以定义内部的Exception,便于判断 if (e instanceof PowerJobException) { ret.setCode(((PowerJobException) e).getCode()); - log.warn("[ControllerException] PowerJobException, message is {}.", ExceptionUtils.getMessage(e)); + log.warn("[ControllerException] PowerJobException, message is {}.", e.getMessage()); } else if (e instanceof IllegalArgumentException) { - log.warn("[ControllerException] http request failed, message is {}.", e.getMessage()); + log.warn("[ControllerException] http request failed due to IllegalArgument, message is {}.", e.getMessage()); } else if (e instanceof HttpMessageNotReadableException || e instanceof MethodArgumentTypeMismatchException) { log.warn("[ControllerException] invalid http request params, exception is {}.", e.getMessage()); } else if (e instanceof HttpRequestMethodNotSupportedException) { diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AppInfoController.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AppInfoController.java index adc0af5b..2f8c6920 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AppInfoController.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AppInfoController.java @@ -2,6 +2,7 @@ package tech.powerjob.server.web.controller; import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.data.domain.Page; @@ -30,8 +31,10 @@ import tech.powerjob.server.web.request.QueryAppInfoRequest; import tech.powerjob.server.web.response.AppInfoVO; import javax.persistence.criteria.Predicate; +import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; /** @@ -102,11 +105,18 @@ public class AppInfoController { Pageable pageable = PageRequest.of(queryAppInfoRequest.getIndex(), queryAppInfoRequest.getPageSize()); - // TODO: 我有权限的列表 + // 相关权限(先查处关联 ids) + Set queryAppIds; + Boolean showMyRelated = queryAppInfoRequest.getShowMyRelated(); + if (BooleanUtils.isTrue(showMyRelated)) { + queryAppIds = webAuthService.fetchMyPermissionTargets(RoleScope.APP); + } else { + queryAppIds = Collections.emptySet(); + } + Specification specification = (root, query, criteriaBuilder) -> { List predicates = Lists.newArrayList(); - Long appId = queryAppInfoRequest.getAppId(); Long namespaceId = queryAppInfoRequest.getNamespaceId(); @@ -122,6 +132,10 @@ public class AppInfoController { predicates.add(criteriaBuilder.like(root.get("appName"), QueryConvertUtils.convertLikeParams(queryAppInfoRequest.getAppNameLike()))); } + if (!queryAppIds.isEmpty()) { + predicates.add(criteriaBuilder.in(root.get("id")).value(queryAppIds)); + } + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); }; diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/NamespaceController.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/NamespaceController.java index 41867de9..b7a199ce 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/NamespaceController.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/NamespaceController.java @@ -2,12 +2,14 @@ package tech.powerjob.server.web.controller; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.web.bind.annotation.*; +import tech.powerjob.common.exception.PowerJobException; import tech.powerjob.common.response.ResultDTO; import tech.powerjob.server.auth.LoginUserHolder; import tech.powerjob.server.auth.Permission; @@ -17,10 +19,13 @@ import tech.powerjob.server.auth.interceptor.ApiPermission; import tech.powerjob.server.auth.plugin.ModifyOrCreateDynamicPermission; import tech.powerjob.server.auth.plugin.SaveNamespaceGrantPermissionPlugin; import tech.powerjob.server.auth.service.WebAuthService; +import tech.powerjob.server.common.SJ; import tech.powerjob.server.common.constants.SwitchableStatus; import tech.powerjob.server.persistence.PageResult; import tech.powerjob.server.persistence.QueryConvertUtils; +import tech.powerjob.server.persistence.remote.model.AppInfoDO; import tech.powerjob.server.persistence.remote.model.NamespaceDO; +import tech.powerjob.server.persistence.remote.repository.AppInfoRepository; import tech.powerjob.server.persistence.remote.repository.NamespaceRepository; import tech.powerjob.server.web.converter.NamespaceConverter; import tech.powerjob.server.web.request.ComponentUserRoleInfo; @@ -51,6 +56,8 @@ public class NamespaceController { @Resource private WebAuthService webAuthService; @Resource + private AppInfoRepository appInfoRepository; + @Resource private NamespaceRepository namespaceRepository; @ResponseBody @@ -102,6 +109,13 @@ public class NamespaceController { @DeleteMapping("/delete") @ApiPermission(name = "Namespace-Delete", roleScope = RoleScope.NAMESPACE, requiredPermission = Permission.SU) public ResultDTO deleteNamespace(Long id) { + + List appInfosInNamespace = appInfoRepository.findAllByNamespaceId(id); + if (CollectionUtils.isNotEmpty(appInfosInNamespace)) { + List relatedApps = appInfosInNamespace.stream().map(AppInfoDO::getAppName).collect(Collectors.toList()); + throw new PowerJobException("Unable to delete due to associated apps: " + SJ.COMMA_JOINER.join(relatedApps)); + } + namespaceRepository.deleteById(id); return ResultDTO.success(null); }