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 new file mode 100644 index 00000000..9f246f8c --- /dev/null +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/utils/HttpServletUtils.java @@ -0,0 +1,27 @@ +package tech.powerjob.server.auth.common.utils; + +import tech.powerjob.common.OmsConstant; + +import javax.servlet.http.HttpServletRequest; + +/** + * HttpServletUtils + * + * @author tjq + * @since 2024/2/12 + */ +public class HttpServletUtils { + + public static String fetchFromHeader(String key, HttpServletRequest httpServletRequest) { + // header、cookie 都能获取 + String v = httpServletRequest.getHeader(key); + + // 解决 window.localStorage.getItem 为 null 的问题 + if (OmsConstant.NULL.equalsIgnoreCase(v)) { + return null; + } + + return v; + } + +} diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/interceptor/PowerJobAuthInterceptor.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/interceptor/PowerJobAuthInterceptor.java index b5abdb42..6774fcad 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/interceptor/PowerJobAuthInterceptor.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/interceptor/PowerJobAuthInterceptor.java @@ -1,13 +1,21 @@ package tech.powerjob.server.auth.interceptor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; +import tech.powerjob.common.exception.ImpossibleException; import tech.powerjob.common.exception.PowerJobException; import tech.powerjob.server.auth.LoginUserHolder; +import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.PowerJobUser; +import tech.powerjob.server.auth.RoleScope; +import tech.powerjob.server.auth.common.AuthErrorCode; +import tech.powerjob.server.auth.common.PowerJobAuthException; +import tech.powerjob.server.auth.common.utils.HttpServletUtils; import tech.powerjob.server.auth.service.login.PowerJobLoginService; import tech.powerjob.server.auth.service.permission.PowerJobPermissionService; import tech.powerjob.server.common.Loggers; @@ -24,6 +32,7 @@ import java.util.Optional; * @author tjq * @since 2023/3/25 */ +@Slf4j @Component public class PowerJobAuthInterceptor implements HandlerInterceptor { @Resource @@ -48,11 +57,9 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor { // 尝试直接解析登陆 final Optional loginUserOpt = powerJobLoginService.ifLogin(request); - // 未登录前先使用302重定向到登录页面 TODO: 前端登录还是服务端直接跳转有待考虑 + // 未登录直接报错,返回固定状态码,前端拦截后跳转到登录页 if (!loginUserOpt.isPresent()) { - response.setStatus(302); - response.setHeader("location", request.getContextPath() + "/login"); - return false; + throw new PowerJobAuthException(AuthErrorCode.USER_NOT_LOGIN); } // 登陆用户进行权限校验 @@ -61,7 +68,27 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor { // 写入上下文 LoginUserHolder.set(powerJobUser); - final boolean hasPermission = powerJobPermissionService.hasPermission(request, handler, powerJobUser, apiPermissionAnno); + Permission requiredPermission = parsePermission(request, handler, apiPermissionAnno); + RoleScope roleScope = apiPermissionAnno.roleScope(); + Long targetId = null; + + if (RoleScope.NAMESPACE.equals(roleScope)) { + + final String namespaceIdStr = HttpServletUtils.fetchFromHeader("NamespaceId", request); + if (StringUtils.isNotEmpty(namespaceIdStr)) { + targetId = Long.valueOf(namespaceIdStr); + } + } + + if (RoleScope.APP.equals(roleScope)) { + final String appIdStr = HttpServletUtils.fetchFromHeader("AppId", request); + if (StringUtils.isNotEmpty(appIdStr)) { + targetId = Long.valueOf(appIdStr); + } + } + + + final boolean hasPermission = powerJobPermissionService.hasPermission(powerJobUser.getId(), roleScope, targetId, requiredPermission); if (hasPermission) { return true; } @@ -90,4 +117,19 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor { } return "UNKNOWN"; } + + private static Permission parsePermission(HttpServletRequest request, Object handler, ApiPermission apiPermission) { + Class dynamicPermissionPlugin = apiPermission.dynamicPermissionPlugin(); + if (EmptyPlugin.class.equals(dynamicPermissionPlugin)) { + return apiPermission.requiredPermission(); + } + try { + DynamicPermissionPlugin dynamicPermission = dynamicPermissionPlugin.getDeclaredConstructor().newInstance(); + return dynamicPermission.calculate(request, handler); + } catch (Throwable t) { + log.error("[PowerJobAuthService] process dynamicPermissionPlugin failed!", t); + ExceptionUtils.rethrow(t); + } + throw new ImpossibleException(); + } } diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java index 1003b266..f20673cc 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java @@ -7,11 +7,11 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import tech.powerjob.common.OmsConstant; import tech.powerjob.server.auth.PowerJobUser; import tech.powerjob.server.auth.common.AuthConstants; import tech.powerjob.server.auth.common.AuthErrorCode; import tech.powerjob.server.auth.common.PowerJobAuthException; +import tech.powerjob.server.auth.common.utils.HttpServletUtils; import tech.powerjob.server.auth.jwt.JwtService; import tech.powerjob.server.auth.login.LoginTypeInfo; import tech.powerjob.server.auth.login.ThirdPartyLoginRequest; @@ -140,12 +140,7 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService { private Optional parseUserName(HttpServletRequest httpServletRequest) { // header、cookie 都能获取 - String jwtStr = httpServletRequest.getHeader(AuthConstants.JWT_NAME); - - // 解决 window.localStorage.getItem 为 null 的问题 - if (OmsConstant.NULL.equalsIgnoreCase(jwtStr)) { - jwtStr = null; - } + String jwtStr = HttpServletUtils.fetchFromHeader(AuthConstants.JWT_NAME, httpServletRequest); if (StringUtils.isEmpty(jwtStr)) { for (Cookie cookie : Optional.ofNullable(httpServletRequest.getCookies()).orElse(new Cookie[]{})) { 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 44cb149d..0d49f9d5 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 @@ -1,11 +1,11 @@ package tech.powerjob.server.auth.service.permission; -import tech.powerjob.server.auth.PowerJobUser; +import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.Role; import tech.powerjob.server.auth.RoleScope; -import tech.powerjob.server.auth.interceptor.ApiPermission; -import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; /** * PowerJob 鉴权服务 @@ -15,15 +15,16 @@ import javax.servlet.http.HttpServletRequest; */ public interface PowerJobPermissionService { + /** * 判断用户是否有访问权限 - * @param request 上下文请求 - * @param handler hander - * @param user 用户 - * @param apiPermission 权限描述 - * @return true or false + * @param userId userId + * @param roleScope 权限范围 + * @param target 权限目标ID + * @param permission 要求的权限 + * @return 是否有权限 */ - boolean hasPermission(HttpServletRequest request, Object handler, PowerJobUser user, ApiPermission apiPermission); + boolean hasPermission(Long userId, RoleScope roleScope, Long target, Permission permission); /** * 授予用户权限 @@ -34,4 +35,21 @@ public interface PowerJobPermissionService { * @param extra 其他 */ void grantPermission(RoleScope roleScope, Long target, Long userId, Role role, String extra); + + /** + * 回收用户权限 + * @param roleScope 权限范围 + * @param target 权限目标 + * @param userId 用户ID + * @param role 角色 + */ + void retrievePermission(RoleScope roleScope, Long target, Long userId, Role role); + + /** + * 获取有相关权限的用户 + * @param roleScope 权限范围 + * @param target 目标 + * @return 角色对应的用户列表 + */ + Map> fetchUserWithPermissions(RoleScope roleScope, Long target); } 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 92a351ff..1c0f67eb 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 @@ -1,27 +1,20 @@ package tech.powerjob.server.auth.service.permission; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.stereotype.Service; -import tech.powerjob.common.exception.ImpossibleException; import tech.powerjob.server.auth.Permission; -import tech.powerjob.server.auth.PowerJobUser; import tech.powerjob.server.auth.Role; import tech.powerjob.server.auth.RoleScope; -import tech.powerjob.server.auth.interceptor.ApiPermission; -import tech.powerjob.server.auth.interceptor.DynamicPermissionPlugin; -import tech.powerjob.server.auth.interceptor.EmptyPlugin; import tech.powerjob.server.persistence.remote.model.AppInfoDO; import tech.powerjob.server.persistence.remote.model.UserRoleDO; import tech.powerjob.server.persistence.remote.repository.AppInfoRepository; import tech.powerjob.server.persistence.remote.repository.UserRoleRepository; import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; import java.util.*; /** @@ -40,8 +33,8 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService private UserRoleRepository userRoleRepository; @Override - public boolean hasPermission(HttpServletRequest request, Object handler, PowerJobUser user, ApiPermission apiPermission) { - final List userRoleList = Optional.ofNullable(userRoleRepository.findAllByUserId(user.getId())).orElse(Collections.emptyList()); + public boolean hasPermission(Long userId, RoleScope roleScope, Long target, Permission requiredPermission) { + final List userRoleList = Optional.ofNullable(userRoleRepository.findAllByUserId(userId)).orElse(Collections.emptyList()); Multimap appId2Role = ArrayListMultimap.create(); Multimap namespaceId2Role = ArrayListMultimap.create(); @@ -50,7 +43,6 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService for (UserRoleDO userRole : userRoleList) { final Role role = Role.of(userRole.getRole()); - RoleScope roleScope = RoleScope.of(userRole.getScope()); // 处理全局权限 if (RoleScope.GLOBAL.equals(roleScope)) { @@ -69,7 +61,6 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService } // 前置判断需要的权限(新增场景还没有 appId or namespaceId) - final Permission requiredPermission = parsePermission(request, handler, apiPermission); if (requiredPermission == Permission.NONE) { return true; } @@ -82,12 +73,12 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService } // 无超级管理员权限,校验普通权限 - if (RoleScope.APP.equals(apiPermission.roleScope())) { - return checkAppPermission(request, requiredPermission, appId2Role, namespaceId2Role); + if (RoleScope.APP.equals(roleScope)) { + return checkAppPermission(target, requiredPermission, appId2Role, namespaceId2Role); } - if (RoleScope.NAMESPACE.equals(apiPermission.roleScope())) { - return checkNamespacePermission(request, requiredPermission, namespaceId2Role); + if (RoleScope.NAMESPACE.equals(roleScope)) { + return checkNamespacePermission(target, requiredPermission, namespaceId2Role); } return false; @@ -110,15 +101,31 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService log.info("[PowerJobPermissionService] saveAndFlush userRole successfully: {}", userRoleDO); } - private boolean checkAppPermission(HttpServletRequest request, Permission requiredPermission, Multimap appId2Role, Multimap namespaceId2Role) { - final String appIdStr = request.getHeader("appId"); - if (StringUtils.isEmpty(appIdStr)) { - throw new IllegalArgumentException("can't find appId in header, please refresh and try again!"); - } + @Override + public void retrievePermission(RoleScope roleScope, Long target, Long userId, Role role) { + List originUserRole = userRoleRepository.findAllByScopeAndTargetAndRoleAndUserId(roleScope.getV(), target, role.getV(), userId); + log.info("[PowerJobPermissionService] [retrievePermission] origin rule: {}", originUserRole); + Optional.ofNullable(originUserRole).orElse(Collections.emptyList()).forEach(r -> { + userRoleRepository.deleteById(r.getId()); + log.info("[PowerJobPermissionService] [retrievePermission] delete UserRole: {}", r); + }); + } - Long appId = Long.valueOf(appIdStr); + @Override + public Map> fetchUserWithPermissions(RoleScope roleScope, Long target) { + List permissionUserList = userRoleRepository.findAllByScopeAndTarget(roleScope.getV(), target); + Map> ret = Maps.newHashMap(); + Optional.ofNullable(permissionUserList).orElse(Collections.emptyList()).forEach(userRoleDO -> { + Role role = Role.of(userRoleDO.getRole()); + List userIds = ret.computeIfAbsent(role, ignore -> Lists.newArrayList()); + userIds.add(userRoleDO.getUserId()); + }); + return ret; + } - final Collection appRoles = appId2Role.get(appId); + private boolean checkAppPermission(Long targetId, Permission requiredPermission, Multimap appId2Role, Multimap namespaceId2Role) { + + final Collection appRoles = appId2Role.get(targetId); for (Role role : appRoles) { if (role.getPermissions().contains(requiredPermission)) { return true; @@ -126,9 +133,9 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService } // 校验 namespace 穿透权限 - Optional appInfoOpt = appInfoRepository.findById(appId); + Optional appInfoOpt = appInfoRepository.findById(targetId); if (!appInfoOpt.isPresent()) { - throw new IllegalArgumentException("can't find appInfo by appId in permission check: " + appId); + throw new IllegalArgumentException("can't find appInfo by appId in permission check: " + targetId); } Long namespaceId = Optional.ofNullable(appInfoOpt.get().getNamespaceId()).orElse(-1L); Collection namespaceRoles = namespaceId2Role.get(namespaceId); @@ -141,14 +148,8 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService return false; } - private boolean checkNamespacePermission(HttpServletRequest request, Permission requiredPermission, Multimap namespaceId2Role) { - final String namespaceIdStr = request.getHeader("namespaceId"); - if (StringUtils.isEmpty(namespaceIdStr)) { - throw new IllegalArgumentException("can't find namespace in header, please refresh and try again!"); - } - Long namespaceId = Long.valueOf(namespaceIdStr); - - Collection namespaceRoles = namespaceId2Role.get(namespaceId); + private boolean checkNamespacePermission(Long targetId, Permission requiredPermission, Multimap namespaceId2Role) { + Collection namespaceRoles = namespaceId2Role.get(targetId); for (Role role : namespaceRoles) { if (role.getPermissions().contains(requiredPermission)) { return true; @@ -158,20 +159,4 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService return false; } - - - private static Permission parsePermission(HttpServletRequest request, Object handler, ApiPermission apiPermission) { - Class dynamicPermissionPlugin = apiPermission.dynamicPermissionPlugin(); - if (EmptyPlugin.class.equals(dynamicPermissionPlugin)) { - return apiPermission.requiredPermission(); - } - try { - DynamicPermissionPlugin dynamicPermission = dynamicPermissionPlugin.getDeclaredConstructor().newInstance(); - return dynamicPermission.calculate(request, handler); - } catch (Throwable t) { - log.error("[PowerJobAuthService] process dynamicPermissionPlugin failed!", t); - ExceptionUtils.rethrow(t); - } - throw new ImpossibleException(); - } } 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 18949f08..6a630caa 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 @@ -16,4 +16,6 @@ public interface UserRoleRepository extends JpaRepository { List findAllByUserId(Long userId); List findAllByScopeAndTarget(Integer scope, Long target); + + List findAllByScopeAndTargetAndRoleAndUserId(Integer scope, Long target, Integer role, Long userId); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/dp/GrantDynamicPermission.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/dp/GrantDynamicPermission.java deleted file mode 100644 index a26bbdbe..00000000 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/dp/GrantDynamicPermission.java +++ /dev/null @@ -1,43 +0,0 @@ -package tech.powerjob.server.auth.dp; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.StreamUtils; -import tech.powerjob.common.serialize.JsonUtils; -import tech.powerjob.server.auth.Permission; -import tech.powerjob.server.auth.Role; -import tech.powerjob.server.auth.interceptor.DynamicPermissionPlugin; -import tech.powerjob.server.web.request.GrantPermissionRequest; - -import javax.servlet.http.HttpServletRequest; - -/** - * 授权动态权限计算 - * 授予权限要低于或等于授权人自身的权限 - * - * @author tjq - * @since 2024/2/12 - */ -@Slf4j -public class GrantDynamicPermission implements DynamicPermissionPlugin { - @Override - public Permission calculate(HttpServletRequest request, Object handler) { - try { - //获取请求body - byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream()); - String body = new String(bodyBytes, request.getCharacterEncoding()); - GrantPermissionRequest grantPermissionRequest = JsonUtils.parseObject(body, GrantPermissionRequest.class); - Role role = Role.of(grantPermissionRequest.getRole()); - - switch (role) { - case OBSERVER: return Permission.READ; - case QA: return Permission.OPS; - case DEVELOPER: return Permission.WRITE; - } - - } catch (Exception e) { - log.error("[GrantDynamicPermission] check permission failed, please fix the bug!!!", e); - } - - return Permission.SU; - } -} diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/dp/ModifyOrCreateDynamicPermission.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/ModifyOrCreateDynamicPermission.java similarity index 97% rename from powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/dp/ModifyOrCreateDynamicPermission.java rename to powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/ModifyOrCreateDynamicPermission.java index 5d655540..44962eaa 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/dp/ModifyOrCreateDynamicPermission.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/ModifyOrCreateDynamicPermission.java @@ -1,4 +1,4 @@ -package tech.powerjob.server.auth.dp; +package tech.powerjob.server.auth.plugin; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StreamUtils; diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveAppGrantPermissionPlugin.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveAppGrantPermissionPlugin.java similarity index 86% rename from powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveAppGrantPermissionPlugin.java rename to powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveAppGrantPermissionPlugin.java index 38c9deeb..4bffe6fd 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveAppGrantPermissionPlugin.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveAppGrantPermissionPlugin.java @@ -1,4 +1,4 @@ -package tech.powerjob.server.auth.gp; +package tech.powerjob.server.auth.plugin; import tech.powerjob.server.auth.RoleScope; diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveGrantPermissionPlugin.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java similarity index 98% rename from powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveGrantPermissionPlugin.java rename to powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java index ca09dd83..2088d0ee 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveGrantPermissionPlugin.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveGrantPermissionPlugin.java @@ -1,4 +1,4 @@ -package tech.powerjob.server.auth.gp; +package tech.powerjob.server.auth.plugin; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.MapUtils; diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveNamespaceGrantPermissionPlugin.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveNamespaceGrantPermissionPlugin.java similarity index 87% rename from powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveNamespaceGrantPermissionPlugin.java rename to powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveNamespaceGrantPermissionPlugin.java index 7e2b2d7c..955ded5a 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/gp/SaveNamespaceGrantPermissionPlugin.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/plugin/SaveNamespaceGrantPermissionPlugin.java @@ -1,4 +1,4 @@ -package tech.powerjob.server.auth.gp; +package tech.powerjob.server.auth.plugin; import tech.powerjob.server.auth.RoleScope; 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 new file mode 100644 index 00000000..51593027 --- /dev/null +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java @@ -0,0 +1,41 @@ +package tech.powerjob.server.auth.service; + +import tech.powerjob.server.auth.Permission; +import tech.powerjob.server.auth.RoleScope; +import tech.powerjob.server.web.request.ComponentUserRoleInfo; + +/** + * Web Auth 服务 + * 写在 starter 包下,抽取 controller 的公共逻辑 + * (powerjob 的 service/core 包核心处理调度核心逻辑,admin 部分代码收口在 stater 包) + * + * @author tjq + * @since 2024/2/12 + */ +public interface WebAuthService { + + /** + * 处理授权 + * @param roleScope 权限范围 + * @param target 权限目标 + * @param componentUserRoleInfo 人员角色信息 + */ + void processPermissionOnSave(RoleScope roleScope, Long target, ComponentUserRoleInfo componentUserRoleInfo); + + /** + * 获取目标相关权限人员列表 + * @param roleScope 权限范围 + * @param target 权限目标 + * @return ComponentUserRoleInfo + */ + ComponentUserRoleInfo fetchComponentUserRoleInfo(RoleScope roleScope, Long target); + + /** + * 判断当前用户是否有权限 + * @param roleScope 权限范围 + * @param target 权限目标 + * @param permission 要求的权限 + * @return 是否有权限 + */ + boolean hasPermission(RoleScope roleScope, Long target, Permission permission); +} 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 new file mode 100644 index 00000000..506a62e8 --- /dev/null +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java @@ -0,0 +1,93 @@ +package tech.powerjob.server.auth.service.impl; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +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.service.WebAuthService; +import tech.powerjob.server.auth.service.permission.PowerJobPermissionService; +import tech.powerjob.server.web.request.ComponentUserRoleInfo; + +import javax.annotation.Resource; +import java.util.*; + +/** + * WebAuthService + * + * @author tjq + * @since 2024/2/12 + */ +@Slf4j +@Service +public class WebAuthServiceImpl implements WebAuthService { + + @Resource + private PowerJobPermissionService powerJobPermissionService; + + + @Override + public void processPermissionOnSave(RoleScope roleScope, Long target, ComponentUserRoleInfo o) { + ComponentUserRoleInfo componentUserRoleInfo = Optional.ofNullable(o).orElse(new ComponentUserRoleInfo()); + + Map> role2Uids = powerJobPermissionService.fetchUserWithPermissions(roleScope, target); + diffGrant(roleScope, target, Role.OBSERVER, componentUserRoleInfo.getObserver(), role2Uids); + diffGrant(roleScope, target, Role.QA, componentUserRoleInfo.getQa(), role2Uids); + diffGrant(roleScope, target, Role.DEVELOPER, componentUserRoleInfo.getDeveloper(), role2Uids); + diffGrant(roleScope, target, Role.ADMIN, componentUserRoleInfo.getAdmin(), role2Uids); + } + + @Override + public ComponentUserRoleInfo fetchComponentUserRoleInfo(RoleScope roleScope, Long target) { + Map> role2Uids = powerJobPermissionService.fetchUserWithPermissions(roleScope, target); + return new ComponentUserRoleInfo() + .setObserver(role2Uids.getOrDefault(Role.OBSERVER, Collections.emptyList())) + .setQa(role2Uids.getOrDefault(Role.QA, Collections.emptyList())) + .setDeveloper(role2Uids.getOrDefault(Role.DEVELOPER, Collections.emptyList())) + .setAdmin(role2Uids.getOrDefault(Role.ADMIN, Collections.emptyList())); + } + + @Override + public boolean hasPermission(RoleScope roleScope, Long target, Permission permission) { + + PowerJobUser powerJobUser = LoginUserHolder.get(); + if (powerJobUser == null) { + return false; + } + + powerJobPermissionService.hasPermission(powerJobUser.getId(), roleScope, target, permission); + + return false; + } + + private void diffGrant(RoleScope roleScope, Long target, Role role, List uids, Map> originRole2Uids) { + + Set orignUids = Sets.newHashSet(Optional.ofNullable(originRole2Uids.get(role)).orElse(Collections.emptyList())); + Set currentUids = Sets.newHashSet(Optional.ofNullable(uids).orElse(Collections.emptyList())); + + Map extraInfo = Maps.newHashMap(); + extraInfo.put("grantor", LoginUserHolder.getUserName()); + extraInfo.put("source", "diffGrant"); + String extra = JsonUtils.toJSONString(extraInfo); + + Set allIds = Sets.newHashSet(orignUids); + allIds.addAll(currentUids); + + Set allIds2 = Sets.newHashSet(allIds); + + // 在 orignUids 不在 currentUids,需要取消授权 + allIds.removeAll(currentUids); + allIds.forEach(cancelPermissionUid -> { + powerJobPermissionService.retrievePermission(roleScope, target, cancelPermissionUid, role); + log.info("[WebAuthService] [diffGrant] cancelPermission: roleScope={},target={},uid={},role={}", roleScope, target, cancelPermissionUid, role); + }); + + // 在 currentUids 当不在 orignUids,需要增加授权 + allIds2.removeAll(orignUids); + allIds2.forEach(addPermissionUid -> { + powerJobPermissionService.grantPermission(roleScope, target, addPermissionUid, role, extra); + log.info("[WebAuthService] [diffGrant] grantPermission: roleScope={},target={},uid={},role={},extra={}", roleScope, target, addPermissionUid, role, extra); + }); + } +} diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AuthController.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AuthController.java index f7597eeb..cf80e3fd 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AuthController.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/AuthController.java @@ -1,26 +1,18 @@ package tech.powerjob.server.web.controller; -import com.google.common.collect.Maps; import org.springframework.web.bind.annotation.*; import tech.powerjob.common.response.ResultDTO; -import tech.powerjob.common.serialize.JsonUtils; -import tech.powerjob.server.auth.*; +import tech.powerjob.server.auth.PowerJobUser; import tech.powerjob.server.auth.common.AuthConstants; -import tech.powerjob.server.auth.dp.GrantDynamicPermission; -import tech.powerjob.server.auth.interceptor.ApiPermission; import tech.powerjob.server.auth.login.LoginTypeInfo; import tech.powerjob.server.auth.service.login.LoginRequest; import tech.powerjob.server.auth.service.login.PowerJobLoginService; -import tech.powerjob.server.auth.service.permission.PowerJobPermissionService; -import tech.powerjob.server.web.request.GrantPermissionRequest; import javax.annotation.Resource; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; /** @@ -35,8 +27,6 @@ public class AuthController { @Resource private PowerJobLoginService powerJobLoginService; - @Resource - private PowerJobPermissionService powerJobPermissionService; @GetMapping("/supportLoginTypes") public ResultDTO> listSupportLoginTypes() { @@ -94,40 +84,10 @@ public class AuthController { @GetMapping(value = "/ifLogin") public ResultDTO ifLogin(HttpServletRequest httpServletRequest) { final Optional powerJobUser = powerJobLoginService.ifLogin(httpServletRequest); - return powerJobUser.map(ResultDTO::success).orElseGet(() -> ResultDTO.failed("LOGIN_FAILED")); + return powerJobUser.map(ResultDTO::success).orElseGet(() -> ResultDTO.success(null)); } private void fillJwt4LoginUser(PowerJobUser powerJobUser, HttpServletResponse httpServletResponse) { httpServletResponse.addCookie(new Cookie(AuthConstants.JWT_NAME, powerJobUser.getJwtToken())); } - - /* 授权相关 */ - @PostMapping("/grantApp") - @ApiPermission(name = "Auth-GrantAppPermission", roleScope = RoleScope.APP, dynamicPermissionPlugin = GrantDynamicPermission.class) - public ResultDTO grantAppPermission(GrantPermissionRequest grantPermissionRequest) { - grantPermission(RoleScope.APP, grantPermissionRequest); - return ResultDTO.success(null); - } - - @PostMapping("/grantNamespace") - @ApiPermission(name = "Auth-GrantNamespacePermission", roleScope = RoleScope.NAMESPACE, dynamicPermissionPlugin = GrantDynamicPermission.class) - public ResultDTO grantNamespacePermission(GrantPermissionRequest grantPermissionRequest) { - grantPermission(RoleScope.NAMESPACE, grantPermissionRequest); - return ResultDTO.success(null); - } - - private void grantPermission(RoleScope roleScope, GrantPermissionRequest grantPermissionRequest) { - - Role role = Role.of(grantPermissionRequest.getRole()); - - Optional.ofNullable(grantPermissionRequest.getUserIds()).orElse(Collections.emptyList()).forEach(uid -> { - // 记录授权人信息 - Map extraInfo = Maps.newHashMap(); - extraInfo.put("grantor", LoginUserHolder.getUserName()); - String extra = JsonUtils.toJSONString(extraInfo); - - powerJobPermissionService.grantPermission(roleScope, grantPermissionRequest.getTargetId(), uid, role, extra); - }); - - } } 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 5aad80f5..c2c1a4de 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 @@ -1,10 +1,8 @@ package tech.powerjob.server.web.controller; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.BeanUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -13,31 +11,28 @@ import org.springframework.web.bind.annotation.*; import tech.powerjob.common.response.ResultDTO; import tech.powerjob.server.auth.LoginUserHolder; import tech.powerjob.server.auth.Permission; -import tech.powerjob.server.auth.Role; import tech.powerjob.server.auth.RoleScope; -import tech.powerjob.server.auth.dp.ModifyOrCreateDynamicPermission; -import tech.powerjob.server.auth.gp.SaveNamespaceGrantPermissionPlugin; 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.constants.SwitchableStatus; import tech.powerjob.server.persistence.PageResult; import tech.powerjob.server.persistence.QueryConvertUtils; import tech.powerjob.server.persistence.remote.model.NamespaceDO; -import tech.powerjob.server.persistence.remote.model.UserInfoDO; -import tech.powerjob.server.persistence.remote.model.UserRoleDO; import tech.powerjob.server.persistence.remote.repository.NamespaceRepository; -import tech.powerjob.server.persistence.remote.repository.UserInfoRepository; -import tech.powerjob.server.persistence.remote.repository.UserRoleRepository; import tech.powerjob.server.web.converter.NamespaceConverter; -import tech.powerjob.server.web.converter.UserConverter; +import tech.powerjob.server.web.request.ComponentUserRoleInfo; import tech.powerjob.server.web.request.ModifyNamespaceRequest; import tech.powerjob.server.web.request.QueryNamespaceRequest; -import tech.powerjob.server.web.response.NamespaceBaseVO; -import tech.powerjob.server.web.response.NamespaceDetailVO; -import tech.powerjob.server.web.response.UserBaseVO; +import tech.powerjob.server.web.response.NamespaceVO; import javax.annotation.Resource; import javax.persistence.criteria.Predicate; -import java.util.*; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -51,23 +46,24 @@ import java.util.stream.Collectors; @RequestMapping("/namespace") public class NamespaceController { + @Resource + private WebAuthService webAuthService; @Resource private NamespaceRepository namespaceRepository; - @Resource - private UserInfoRepository userInfoRepository; - @Resource - private UserRoleRepository userRoleRepository; @ResponseBody @PostMapping("/save") @ApiPermission(name = "Namespace-Save", roleScope = RoleScope.NAMESPACE, dynamicPermissionPlugin = ModifyOrCreateDynamicPermission.class, grandPermissionPlugin = SaveNamespaceGrantPermissionPlugin.class) - public ResultDTO save(@RequestBody ModifyNamespaceRequest req) { + public ResultDTO save(@RequestBody ModifyNamespaceRequest req) { req.valid(); Long id = req.getId(); NamespaceDO namespaceDO; - if (id == null) { + + boolean isCreate = id == null; + + if (isCreate) { namespaceDO = new NamespaceDO(); namespaceDO.setGmtCreate(new Date()); @@ -80,20 +76,36 @@ public class NamespaceController { } else { namespaceDO = fetchById(id); namespaceDO.setModifier(LoginUserHolder.getUserName()); + + if (!namespaceDO.getCode().equalsIgnoreCase(req.getCode())) { + throw new IllegalArgumentException("NOT_ALLOW_CHANGE_THE_NAMESPACE_CODE"); + } } // 拷贝通用变更属性(code 不允许更改) + namespaceDO.setTags(req.getTags()); namespaceDO.setName(req.getName()); namespaceDO.setExtra(req.getExtra()); namespaceDO.setStatus(Optional.ofNullable(req.getStatus()).orElse(SwitchableStatus.ENABLE.getV())); namespaceDO.setGmtModified(new Date()); NamespaceDO savedNamespace = namespaceRepository.save(namespaceDO); + + // 授权 + webAuthService.processPermissionOnSave(RoleScope.NAMESPACE, savedNamespace.getId(), req.getComponentUserRoleInfo()); + return ResultDTO.success(NamespaceConverter.do2BaseVo(savedNamespace)); } + @DeleteMapping("/delete") + @ApiPermission(name = "Namespace-Delete", roleScope = RoleScope.NAMESPACE, requiredPermission = Permission.SU) + public ResultDTO deleteNamespace(Long id) { + namespaceRepository.deleteById(id); + return ResultDTO.success(null); + } + @PostMapping("/list") - public ResultDTO> listNamespace(@RequestBody QueryNamespaceRequest queryNamespaceRequest) { + public ResultDTO> listNamespace(@RequestBody QueryNamespaceRequest queryNamespaceRequest) { String codeLike = queryNamespaceRequest.getCodeLike(); String nameLike = queryNamespaceRequest.getNameLike(); @@ -123,39 +135,29 @@ public class NamespaceController { Page namespacePageResult = namespaceRepository.findAll(specification, pageable); - PageResult ret = new PageResult<>(namespacePageResult); - ret.setData(namespacePageResult.get().map(NamespaceConverter::do2BaseVo).collect(Collectors.toList())); + PageResult ret = new PageResult<>(namespacePageResult); + ret.setData(namespacePageResult.get().map(x -> { + NamespaceVO namespaceVO = NamespaceConverter.do2BaseVo(x); + fillPermissionInfo(x, namespaceVO); + return namespaceVO; + }).collect(Collectors.toList())); return ResultDTO.success(ret); } - @GetMapping("/detail") - @ApiPermission(name = "Namespace-GetDetail", roleScope = RoleScope.NAMESPACE, requiredPermission = Permission.READ) - public ResultDTO queryNamespaceDetail(Long id) { + private void fillPermissionInfo(NamespaceDO namespaceDO, NamespaceVO namespaceVO) { - NamespaceDO namespaceDO = fetchById(id); - NamespaceDetailVO namespaceDetailVO = new NamespaceDetailVO(); + Long namespaceId = namespaceVO.getId(); - // 拷贝基础字段 - NamespaceBaseVO namespaceBaseVO = NamespaceConverter.do2BaseVo(namespaceDO); - BeanUtils.copyProperties(namespaceBaseVO, namespaceDetailVO); + // 权限用户关系 + ComponentUserRoleInfo componentUserRoleInfo = webAuthService.fetchComponentUserRoleInfo(RoleScope.NAMESPACE, namespaceId); + namespaceVO.setComponentUserRoleInfo(componentUserRoleInfo); - // 处理 token - namespaceDetailVO.setToken(namespaceDO.getToken()); - - // 处理权限视图 - Map> privilegedUsers = Maps.newHashMap(); - namespaceDetailVO.setPrivilegedUsers(privilegedUsers); - List permissionUserList = userRoleRepository.findAllByScopeAndTarget(RoleScope.NAMESPACE.getV(), namespaceDO.getId()); - permissionUserList.forEach(r -> { - Role role = Role.of(r.getRole()); - List userBaseVOList = privilegedUsers.computeIfAbsent(role.name(), ignore -> Lists.newArrayList()); - - Optional userInfoDoOpt = userInfoRepository.findById(r.getUserId()); - userInfoDoOpt.ifPresent(userInfoDO -> userBaseVOList.add(UserConverter.do2BaseVo(userInfoDO))); - }); - - return ResultDTO.success(namespaceDetailVO); + // 有权限用户填充 token + boolean hasPermission = webAuthService.hasPermission(RoleScope.NAMESPACE, namespaceId, Permission.READ); + if (hasPermission) { + namespaceVO.setToken(namespaceDO.getToken()); + } } private NamespaceDO fetchById(Long id) { diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/NamespaceConverter.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/NamespaceConverter.java index 01f968f8..7ef6d7a0 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/NamespaceConverter.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/NamespaceConverter.java @@ -4,7 +4,7 @@ import org.springframework.beans.BeanUtils; import tech.powerjob.common.utils.CommonUtils; import tech.powerjob.server.common.constants.SwitchableStatus; import tech.powerjob.server.persistence.remote.model.NamespaceDO; -import tech.powerjob.server.web.response.NamespaceBaseVO; +import tech.powerjob.server.web.response.NamespaceVO; /** * NamespaceConverter @@ -14,8 +14,8 @@ import tech.powerjob.server.web.response.NamespaceBaseVO; */ public class NamespaceConverter { - public static NamespaceBaseVO do2BaseVo(NamespaceDO d) { - NamespaceBaseVO v = new NamespaceBaseVO(); + public static NamespaceVO do2BaseVo(NamespaceDO d) { + NamespaceVO v = new NamespaceVO(); BeanUtils.copyProperties(d, v); v.setGmtCreateStr(CommonUtils.formatTime(d.getGmtCreate())); v.setGmtModifiedStr(CommonUtils.formatTime(d.getGmtModified())); diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ComponentUserRoleInfo.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ComponentUserRoleInfo.java new file mode 100644 index 00000000..0b2fd925 --- /dev/null +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ComponentUserRoleInfo.java @@ -0,0 +1,34 @@ +package tech.powerjob.server.web.request; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 组件上的用户角色信息 + * + * @author tjq + * @since 2024/2/12 + */ +@Data +@Accessors(chain = true) +public class ComponentUserRoleInfo { + /** + * 观察者 + */ + private List observer; + /** + * 测试 + */ + private List qa; + /** + * 开发者 + */ + private List developer; + /** + * 管理员 + */ + private List admin; + +} diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyNamespaceRequest.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyNamespaceRequest.java index 06bf052e..1edb7eb3 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyNamespaceRequest.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/ModifyNamespaceRequest.java @@ -39,6 +39,10 @@ public class ModifyNamespaceRequest { * 扩展字段 */ private String extra; + /** + * 权限表单 + */ + private ComponentUserRoleInfo componentUserRoleInfo; public void valid() { CommonUtils.requireNonNull(code, "namespace code can't be empty"); diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceDetailVO.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceDetailVO.java deleted file mode 100644 index 2a2eb96f..00000000 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceDetailVO.java +++ /dev/null @@ -1,29 +0,0 @@ -package tech.powerjob.server.web.response; - -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -import java.util.List; -import java.util.Map; - -/** - * 详细命名空间信息,需要权限访问 - * - * @author tjq - * @since 2023/9/3 - */ -@Getter -@Setter -@ToString(callSuper = true) -public class NamespaceDetailVO extends NamespaceBaseVO { - - /** - * 访问 token - */ - private String token; - /** - * 有权限的用户 - */ - private Map> privilegedUsers; -} diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceBaseVO.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceVO.java similarity index 73% rename from powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceBaseVO.java rename to powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceVO.java index 5df3c640..b90c37ec 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceBaseVO.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/NamespaceVO.java @@ -3,6 +3,7 @@ package tech.powerjob.server.web.response; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import tech.powerjob.server.web.request.ComponentUserRoleInfo; import java.io.Serializable; import java.util.Date; @@ -16,7 +17,7 @@ import java.util.Date; @Getter @Setter @ToString -public class NamespaceBaseVO implements Serializable { +public class NamespaceVO implements Serializable { private Long id; @@ -52,4 +53,13 @@ public class NamespaceBaseVO implements Serializable { private String creator; private String modifier; + + /** + * 访问 token + * 仅拥有当前 namespace 权限的访问者可见 + */ + private String token; + + private ComponentUserRoleInfo componentUserRoleInfo; + }