feat: support user related query

This commit is contained in:
tjq 2024-02-13 16:22:56 +08:00
parent 31a7690844
commit c350607762
9 changed files with 83 additions and 5 deletions

View File

@ -47,9 +47,17 @@ public interface PowerJobPermissionService {
/**
* 获取有相关权限的用户
* @param roleScope 权限范围
* @param roleScope 角色范围
* @param target 目标
* @return 角色对应的用户列表
*/
Map<Role, List<Long>> fetchUserWithPermissions(RoleScope roleScope, Long target);
/**
* 获取用户有权限的目标
* @param roleScope 角色范围
* @param userId 用户ID
* @return result
*/
Map<Role, List<Long>> fetchUserHadPermissionTargets(RoleScope roleScope, Long userId);
}

View File

@ -123,6 +123,21 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService
return ret;
}
@Override
public Map<Role, List<Long>> fetchUserHadPermissionTargets(RoleScope roleScope, Long userId) {
Map<Role, List<Long>> ret = Maps.newHashMap();
List<UserRoleDO> userRoleDOList = userRoleRepository.findAllByUserIdAndScope(userId, roleScope.getV());
Optional.ofNullable(userRoleDOList).orElse(Collections.emptyList()).forEach(r -> {
Role role = Role.of(r.getRole());
List<Long> targetIds = ret.computeIfAbsent(role, ignore -> Lists.newArrayList());
targetIds.add(r.getTarget());
});
return ret;
}
private boolean checkAppPermission(Long targetId, Permission requiredPermission, Multimap<Long, Role> appId2Role, Multimap<Long, Role> namespaceId2Role) {
final Collection<Role> appRoles = appId2Role.get(targetId);

View File

@ -32,4 +32,6 @@ public interface AppInfoRepository extends JpaRepository<AppInfoDO, Long>, JpaSp
@Query(value = "select id from AppInfoDO where currentServer = :currentServer")
List<Long> listAppIdByCurrentServer(@Param("currentServer")String currentServer);
List<AppInfoDO> findAllByNamespaceId(Long namespaceId);
}

View File

@ -18,4 +18,6 @@ public interface UserRoleRepository extends JpaRepository<UserRoleDO, Long> {
List<UserRoleDO> findAllByScopeAndTarget(Integer scope, Long target);
List<UserRoleDO> findAllByScopeAndTargetAndRoleAndUserId(Integer scope, Long target, Integer role, Long userId);
List<UserRoleDO> findAllByUserIdAndScope(Long userId, Integer scope);
}

View File

@ -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<Long> fetchMyPermissionTargets(RoleScope roleScope);
}

View File

@ -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<Long> fetchMyPermissionTargets(RoleScope roleScope) {
PowerJobUser powerJobUser = LoginUserHolder.get();
if (powerJobUser == null) {
throw new PowerJobAuthException(AuthErrorCode.USER_NOT_LOGIN);
}
Map<Role, List<Long>> role2TargetIds = powerJobPermissionService.fetchUserHadPermissionTargets(roleScope, powerJobUser.getId());
Set<Long> targetIds = Sets.newHashSet();
role2TargetIds.values().forEach(targetIds::addAll);
// 展示不考虑穿透权限的问题即拥有 namespace 权限也可以看到全部的 apps
return targetIds;
}
private void diffGrant(RoleScope roleScope, Long target, Role role, List<Long> uids, Map<Role, List<Long>> originRole2Uids) {
Set<Long> originUids = Sets.newHashSet(Optional.ofNullable(originRole2Uids.get(role)).orElse(Collections.emptyList()));

View File

@ -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) {

View File

@ -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<Long> queryAppIds;
Boolean showMyRelated = queryAppInfoRequest.getShowMyRelated();
if (BooleanUtils.isTrue(showMyRelated)) {
queryAppIds = webAuthService.fetchMyPermissionTargets(RoleScope.APP);
} else {
queryAppIds = Collections.emptySet();
}
Specification<AppInfoDO> specification = (root, query, criteriaBuilder) -> {
List<Predicate> 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();
};

View File

@ -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<Void> deleteNamespace(Long id) {
List<AppInfoDO> appInfosInNamespace = appInfoRepository.findAllByNamespaceId(id);
if (CollectionUtils.isNotEmpty(appInfosInNamespace)) {
List<String> 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);
}