diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthConstants.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthConstants.java index af14d880..19fcaa40 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthConstants.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthConstants.java @@ -18,4 +18,6 @@ public class AuthConstants { * 前端跳转到指定页面指令 */ public static final String FE_REDIRECT_KEY = "FE-REDIRECT:"; + + public static final String TIPS_NO_PERMISSION_TO_SEE = "NO_PERMISSION_TO_SEE"; } diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/utils/HttpServletUtils.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/utils/HttpServletUtils.java index 9f246f8c..7c232ca1 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/utils/HttpServletUtils.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/utils/HttpServletUtils.java @@ -17,7 +17,7 @@ public class HttpServletUtils { String v = httpServletRequest.getHeader(key); // 解决 window.localStorage.getItem 为 null 的问题 - if (OmsConstant.NULL.equalsIgnoreCase(v)) { + if (OmsConstant.NULL.equalsIgnoreCase(v) || "undefined".equalsIgnoreCase(v)) { return null; } 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 1c0f67eb..3b8495e8 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 @@ -45,17 +45,17 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService final Role role = Role.of(userRole.getRole()); // 处理全局权限 - if (RoleScope.GLOBAL.equals(roleScope)) { + if (RoleScope.GLOBAL.getV() == userRole.getScope()) { if (Role.ADMIN.equals(role)) { return true; } globalRoles.add(role); } - if (Objects.equals(userRole.getScope(), RoleScope.NAMESPACE.getV())) { + if (RoleScope.NAMESPACE.getV() == userRole.getScope()) { namespaceId2Role.put(userRole.getTarget(), role); } - if (Objects.equals(userRole.getScope(), RoleScope.APP.getV())) { + if (RoleScope.APP.getV() == userRole.getScope()) { appId2Role.put(userRole.getTarget(), role); } } @@ -98,7 +98,7 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService userRoleDO.setRole(role.getV()); userRoleRepository.saveAndFlush(userRoleDO); - log.info("[PowerJobPermissionService] saveAndFlush userRole successfully: {}", userRoleDO); + log.info("[PowerJobPermissionService] [grantPermission] saveAndFlush userRole successfully: {}", userRoleDO); } @Override diff --git a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/AppInfoDO.java b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/AppInfoDO.java index 33165261..bd6dee28 100644 --- a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/AppInfoDO.java +++ b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/AppInfoDO.java @@ -22,12 +22,14 @@ public class AppInfoDO { @GenericGenerator(name = "native", strategy = "native") private Long id; - /** - * 命名空间ID,外键关联 - */ - private Long namespaceId; private String appName; + + /** + * 描述 + */ + private String title; + /** * 应用分组密码 */ @@ -40,7 +42,24 @@ public class AppInfoDO { */ private String currentServer; + /** + * 命名空间ID,外键关联 + */ + private Long namespaceId; + /** + * 管理标签 + */ + private String tags; + /** + * 扩展字段 + */ + private String extra; + private Date gmtCreate; private Date gmtModified; + + private String creator; + + private String modifier; } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java index 2088d0ee..3bc273e0 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java @@ -1,5 +1,6 @@ package tech.powerjob.server.auth.plugin; +import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.MapUtils; import tech.powerjob.common.response.ResultDTO; @@ -9,12 +10,10 @@ import tech.powerjob.server.auth.PowerJobUser; import tech.powerjob.server.auth.Role; import tech.powerjob.server.auth.RoleScope; import tech.powerjob.server.auth.interceptor.GrantPermissionPlugin; +import tech.powerjob.server.auth.service.permission.PowerJobPermissionService; import tech.powerjob.server.common.utils.SpringUtils; -import tech.powerjob.server.persistence.remote.model.UserRoleDO; -import tech.powerjob.server.persistence.remote.repository.UserRoleRepository; import java.lang.reflect.Method; -import java.util.Date; import java.util.Map; /** @@ -65,17 +64,12 @@ public abstract class SaveGrantPermissionPlugin implements GrantPermissionPlugin throw new IllegalArgumentException("[GrantPermission] result success but id not exits, maybe there has some bug, please fix it!!!"); } - UserRoleRepository userRoleRepository = SpringUtils.getBean(UserRoleRepository.class); - UserRoleDO userRoleDO = new UserRoleDO(); + PowerJobPermissionService powerJobPermissionService = SpringUtils.getBean(PowerJobPermissionService.class); - userRoleDO.setUserId(powerJobUser.getId()); - userRoleDO.setRole(Role.ADMIN.getV()); - userRoleDO.setScope(fetchRuleScope().getV()); - userRoleDO.setTarget(savedId); - userRoleDO.setGmtCreate(new Date()); - userRoleDO.setGmtModified(new Date()); + Map extra = Maps.newHashMap(); + extra.put("source", "SaveGrantPermissionPlugin"); - userRoleRepository.saveAndFlush(userRoleDO); + powerJobPermissionService.grantPermission(fetchRuleScope(), savedId, powerJobUser.getId(), Role.ADMIN, JsonUtils.toJSONString(extra)); } protected abstract RoleScope fetchRuleScope(); 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 506a62e8..4c35e2e2 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 @@ -56,9 +56,7 @@ public class WebAuthServiceImpl implements WebAuthService { return false; } - powerJobPermissionService.hasPermission(powerJobUser.getId(), roleScope, target, permission); - - return false; + return powerJobPermissionService.hasPermission(powerJobUser.getId(), roleScope, target, permission); } private void diffGrant(RoleScope roleScope, Long target, Role role, List uids, Map> originRole2Uids) { 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 2901332d..e648d078 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 @@ -1,7 +1,6 @@ package tech.powerjob.server.web.controller; import com.google.common.collect.Lists; -import lombok.Data; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; @@ -11,24 +10,30 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; -import tech.powerjob.common.exception.PowerJobException; import tech.powerjob.common.response.ResultDTO; +import tech.powerjob.common.utils.CommonUtils; +import tech.powerjob.server.auth.LoginUserHolder; +import tech.powerjob.server.auth.Permission; +import tech.powerjob.server.auth.RoleScope; +import tech.powerjob.server.auth.common.AuthConstants; +import tech.powerjob.server.auth.interceptor.ApiPermission; +import tech.powerjob.server.auth.plugin.ModifyOrCreateDynamicPermission; +import tech.powerjob.server.auth.plugin.SaveAppGrantPermissionPlugin; +import tech.powerjob.server.auth.service.WebAuthService; import tech.powerjob.server.core.service.AppInfoService; 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.repository.AppInfoRepository; import tech.powerjob.server.web.request.AppAssertRequest; +import tech.powerjob.server.web.request.ComponentUserRoleInfo; import tech.powerjob.server.web.request.ModifyAppInfoRequest; import tech.powerjob.server.web.request.QueryAppInfoRequest; +import tech.powerjob.server.web.response.AppInfoVO; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; import java.util.Date; import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; /** @@ -43,6 +48,8 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class AppInfoController { + private final WebAuthService webAuthService; + private final AppInfoService appInfoService; private final AppInfoRepository appInfoRepository; @@ -50,6 +57,7 @@ public class AppInfoController { private static final int MAX_APP_NUM = 200; @PostMapping("/save") + @ApiPermission(name = "App-Save", roleScope = RoleScope.APP, dynamicPermissionPlugin = ModifyOrCreateDynamicPermission.class, grandPermissionPlugin = SaveAppGrantPermissionPlugin.class) public ResultDTO saveAppInfo(@RequestBody ModifyAppInfoRequest req) { req.valid(); @@ -59,73 +67,73 @@ public class AppInfoController { if (id == null) { appInfoDO = new AppInfoDO(); appInfoDO.setGmtCreate(new Date()); - }else { + appInfoDO.setCreator(LoginUserHolder.getUserName()); + } else { appInfoDO = appInfoRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("can't find appInfo by id:" + id)); - // 对比密码 - if (!Objects.equals(req.getOldPassword(), appInfoDO.getPassword())) { - throw new PowerJobException("The password is incorrect."); + // 不允许修改 appName + if (!appInfoDO.getAppName().equalsIgnoreCase(req.getAppName())) { + throw new IllegalArgumentException("NOT_ALLOW_CHANGE_THE_APP_NAME"); } } - BeanUtils.copyProperties(req, appInfoDO); + + appInfoDO.setAppName(req.getAppName()); + appInfoDO.setTitle(req.getTitle()); + appInfoDO.setPassword(req.getPassword()); + appInfoDO.setNamespaceId(req.getNamespaceId()); + appInfoDO.setTags(req.getTags()); + appInfoDO.setExtra(req.getExtra()); + appInfoDO.setGmtModified(new Date()); + appInfoDO.setModifier(LoginUserHolder.getUserName()); AppInfoDO savedAppInfo = appInfoRepository.saveAndFlush(appInfoDO); + + // 重现授权 + webAuthService.processPermissionOnSave(RoleScope.APP, savedAppInfo.getId(), req.getComponentUserRoleInfo()); + return ResultDTO.success(convert(Lists.newArrayList(savedAppInfo), false).get(0)); } + @GetMapping("/delete") + @ApiPermission(name = "App-Delete", roleScope = RoleScope.APP, requiredPermission = Permission.SU) + public ResultDTO deleteAppInfo(Long appId) { + appInfoRepository.deleteById(appId); + return ResultDTO.success(null); + } + @PostMapping("/assert") public ResultDTO assertApp(@RequestBody AppAssertRequest request) { return ResultDTO.success(appInfoService.assertApp(request.getAppName(), request.getPassword())); } - @GetMapping("/delete") - public ResultDTO deleteAppInfo(Long appId) { - appInfoRepository.deleteById(appId); - return ResultDTO.success(null); - } - - @GetMapping("/list") - public ResultDTO> listAppInfo(@RequestParam(required = false) String condition) { - List result; - Pageable limit = PageRequest.of(0, MAX_APP_NUM); - if (StringUtils.isEmpty(condition)) { - result = appInfoRepository.findAll(limit).getContent(); - }else { - result = appInfoRepository.findByAppNameLike("%" + condition + "%", limit).getContent(); - } - return ResultDTO.success(convert(result, false)); - } - - @PostMapping("/listByQuery") - public ResultDTO> listAppInfoByQuery(QueryAppInfoRequest queryAppInfoRequest) { + @PostMapping("/list") + @ApiPermission(name = "Namespace-List", roleScope = RoleScope.APP, requiredPermission = Permission.NONE) + public ResultDTO> listAppInfoByQuery(@RequestBody QueryAppInfoRequest queryAppInfoRequest) { Pageable pageable = PageRequest.of(queryAppInfoRequest.getIndex(), queryAppInfoRequest.getPageSize()); // TODO: 我有权限的列表 - Specification specification = new Specification() { - @Override - public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { - List predicates = Lists.newArrayList(); + Specification specification = (root, query, criteriaBuilder) -> { + List predicates = Lists.newArrayList(); - Long appId = queryAppInfoRequest.getAppId(); - Long namespaceId = queryAppInfoRequest.getNamespaceId(); + Long appId = queryAppInfoRequest.getAppId(); + Long namespaceId = queryAppInfoRequest.getNamespaceId(); - if (appId != null) { - predicates.add(criteriaBuilder.equal(root.get("id"), appId)); - } - - if (namespaceId != null) { - predicates.add(criteriaBuilder.equal(root.get("namespaceId"), namespaceId)); - } - - if (StringUtils.isNotEmpty(queryAppInfoRequest.getAppName())) { - predicates.add(criteriaBuilder.like(root.get("appName"), QueryConvertUtils.convertLikeParams(queryAppInfoRequest.getAppName()))); - } - - return query.where(predicates.toArray(new Predicate[0])).getRestriction(); + if (appId != null) { + predicates.add(criteriaBuilder.equal(root.get("id"), appId)); } + + if (namespaceId != null) { + predicates.add(criteriaBuilder.equal(root.get("namespaceId"), namespaceId)); + } + + if (StringUtils.isNotEmpty(queryAppInfoRequest.getAppNameLike())) { + predicates.add(criteriaBuilder.like(root.get("appName"), QueryConvertUtils.convertLikeParams(queryAppInfoRequest.getAppNameLike()))); + } + + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); }; Page pageAppInfoResult = appInfoRepository.findAll(specification, pageable); @@ -139,27 +147,30 @@ public class AppInfoController { } - private static List convert(List data, boolean fillDetail) { + private List convert(List data, boolean fillDetail) { if (CollectionUtils.isEmpty(data)) { return Lists.newLinkedList(); } - List appInfoVOList = data.stream().map(appInfoDO -> { + + return data.stream().map(appInfoDO -> { AppInfoVO appInfoVO = new AppInfoVO(); BeanUtils.copyProperties(appInfoDO, appInfoVO); + + appInfoVO.setGmtCreateStr(CommonUtils.formatTime(appInfoDO.getGmtCreate())); + appInfoVO.setGmtModifiedStr(CommonUtils.formatTime(appInfoDO.getGmtModified())); + + if (fillDetail) { + // 人员面板 + ComponentUserRoleInfo componentUserRoleInfo = webAuthService.fetchComponentUserRoleInfo(RoleScope.APP, appInfoDO.getId()); + appInfoVO.setComponentUserRoleInfo(componentUserRoleInfo); + + // 密码 + boolean hasPermission = webAuthService.hasPermission(RoleScope.APP, appInfoDO.getId(), Permission.READ); + appInfoVO.setPassword(hasPermission ? appInfoDO.getPassword() : AuthConstants.TIPS_NO_PERMISSION_TO_SEE); + } + return appInfoVO; }).collect(Collectors.toList()); - - if (fillDetail) { - // TODO: 补全权限等额外信息 - } - - return appInfoVOList; - } - - @Data - private static class AppInfoVO { - private Long id; - private String appName; } } 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 c2c1a4de..2ec02031 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 @@ -12,6 +12,7 @@ import tech.powerjob.common.response.ResultDTO; import tech.powerjob.server.auth.LoginUserHolder; import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.RoleScope; +import tech.powerjob.server.auth.common.AuthConstants; import tech.powerjob.server.auth.interceptor.ApiPermission; import tech.powerjob.server.auth.plugin.ModifyOrCreateDynamicPermission; import tech.powerjob.server.auth.plugin.SaveNamespaceGrantPermissionPlugin; @@ -105,6 +106,7 @@ public class NamespaceController { } @PostMapping("/list") + @ApiPermission(name = "Namespace-List", roleScope = RoleScope.NAMESPACE, requiredPermission = Permission.NONE) public ResultDTO> listNamespace(@RequestBody QueryNamespaceRequest queryNamespaceRequest) { String codeLike = queryNamespaceRequest.getCodeLike(); @@ -155,9 +157,7 @@ public class NamespaceController { // 有权限用户填充 token boolean hasPermission = webAuthService.hasPermission(RoleScope.NAMESPACE, namespaceId, Permission.READ); - if (hasPermission) { - namespaceVO.setToken(namespaceDO.getToken()); - } + namespaceVO.setToken(hasPermission ? namespaceDO.getToken() : AuthConstants.TIPS_NO_PERMISSION_TO_SEE); } private NamespaceDO fetchById(Long id) { diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyAppInfoRequest.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyAppInfoRequest.java index 2b5aca6f..6571b0ac 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyAppInfoRequest.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyAppInfoRequest.java @@ -15,14 +15,34 @@ import org.apache.commons.lang3.StringUtils; public class ModifyAppInfoRequest { private Long id; - private String oldPassword; private String appName; + + private Long namespaceId; + + private String oldPassword; private String password; + /** + * 描述 + */ + private String title; + + /** + * 管理标签 + */ + private String tags; + /** + * 扩展字段 + */ + private String extra; + + private ComponentUserRoleInfo componentUserRoleInfo; + public void valid() { CommonUtils.requireNonNull(appName, "appName can't be empty"); if (StringUtils.containsWhitespace(appName)) { throw new PowerJobException("appName can't contains white space!"); } + CommonUtils.requireNonNull(password, "password can't be empty"); } } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryAppInfoRequest.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryAppInfoRequest.java index 28ca91d9..44f2886a 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryAppInfoRequest.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryAppInfoRequest.java @@ -22,7 +22,9 @@ public class QueryAppInfoRequest { /** * 任务名称 */ - private String appName; + private String appNameLike; + + private String tagLike; /** * 查询与我相关的任务(我有直接权限的) diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/AppInfoVO.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/AppInfoVO.java new file mode 100644 index 00000000..12bbba18 --- /dev/null +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/AppInfoVO.java @@ -0,0 +1,46 @@ +package tech.powerjob.server.web.response; + +import lombok.Data; +import tech.powerjob.server.web.request.ComponentUserRoleInfo; + +import java.io.Serializable; +import java.util.Date; + +/** + * AppInfoVO + * + * @author tjq + * @since 2024/2/12 + */ +@Data +public class AppInfoVO implements Serializable { + + private Long id; + + private String appName; + + /** + * 描述 + */ + private String title; + + private String password; + + private String tags; + + private String extra; + + private ComponentUserRoleInfo componentUserRoleInfo; + + private Date gmtCreate; + + private String gmtCreateStr; + + private Date gmtModified; + + private String gmtModifiedStr; + + private String creator; + + private String modifier; +}