mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: [auth] grant permission
This commit is contained in:
parent
3fdcc1e599
commit
841c7891c8
@ -1,13 +1,20 @@
|
||||
package tech.powerjob.common.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* PowerJob 运行时异常
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2020/5/26
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class PowerJobException extends RuntimeException {
|
||||
|
||||
protected String code;
|
||||
|
||||
public PowerJobException() {
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
public class ResultDTO<T> implements PowerSerializable {
|
||||
|
||||
private boolean success;
|
||||
private String code;
|
||||
private T data;
|
||||
private String message;
|
||||
|
||||
|
@ -21,4 +21,16 @@ public class LoginUserHolder {
|
||||
public static void clean() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户名
|
||||
* @return 存在则返回常规用户名,否则返回 unknown
|
||||
*/
|
||||
public static String getUserName() {
|
||||
PowerJobUser powerJobUser = get();
|
||||
if (powerJobUser != null) {
|
||||
return powerJobUser.getUsername();
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
@ -12,17 +12,12 @@ import tech.powerjob.common.exception.PowerJobException;
|
||||
@Getter
|
||||
public class PowerJobAuthException extends PowerJobException {
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String msg;
|
||||
|
||||
public PowerJobAuthException(AuthErrorCode errorCode) {
|
||||
this.code = errorCode.getCode();
|
||||
this.msg = errorCode.getMsg();
|
||||
this(errorCode, null);
|
||||
}
|
||||
|
||||
public PowerJobAuthException(AuthErrorCode errorCode, String extraMsg) {
|
||||
super(extraMsg == null ? errorCode.getMsg() : errorCode.getMsg().concat(":").concat(extraMsg));
|
||||
this.code = errorCode.getCode();
|
||||
this.msg = errorCode.getMsg().concat(":").concat(extraMsg);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,6 @@ package tech.powerjob.server.auth.interceptor;
|
||||
|
||||
import tech.powerjob.server.auth.Permission;
|
||||
import tech.powerjob.server.auth.RoleScope;
|
||||
import tech.powerjob.server.auth.interceptor.dp.DynamicPermission;
|
||||
import tech.powerjob.server.auth.interceptor.dp.EmptyDynamicPermission;
|
||||
import tech.powerjob.server.auth.interceptor.gp.EmptyGrantPermissionPlugin;
|
||||
import tech.powerjob.server.auth.interceptor.gp.GrantPermissionPlugin;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@ -39,11 +35,11 @@ public @interface ApiPermission {
|
||||
* 固定权限不支持的场景,需要使用动态权限
|
||||
* @return 动态权限
|
||||
*/
|
||||
Class<? extends DynamicPermission> dynamicPermissionPlugin() default EmptyDynamicPermission.class;
|
||||
Class<? extends DynamicPermissionPlugin> dynamicPermissionPlugin() default EmptyPlugin.class;
|
||||
|
||||
/**
|
||||
* 新增场景,需要授权插件执行授权
|
||||
* @return 授权插件
|
||||
*/
|
||||
Class<? extends GrantPermissionPlugin> grandPermissionPlugin() default EmptyGrantPermissionPlugin.class;
|
||||
Class<? extends GrantPermissionPlugin> grandPermissionPlugin() default EmptyPlugin.class;
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import tech.powerjob.server.auth.interceptor.gp.GrantPermissionPlugin;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package tech.powerjob.server.auth.interceptor.dp;
|
||||
package tech.powerjob.server.auth.interceptor;
|
||||
|
||||
import tech.powerjob.server.auth.Permission;
|
||||
|
||||
@ -10,6 +10,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
* @author tjq
|
||||
* @since 2023/9/3
|
||||
*/
|
||||
public interface DynamicPermission {
|
||||
public interface DynamicPermissionPlugin {
|
||||
Permission calculate(HttpServletRequest request, Object handler);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package tech.powerjob.server.auth.interceptor;
|
||||
|
||||
import tech.powerjob.server.auth.Permission;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 空
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/12
|
||||
*/
|
||||
public class EmptyPlugin implements DynamicPermissionPlugin, GrantPermissionPlugin {
|
||||
@Override
|
||||
public Permission calculate(HttpServletRequest request, Object handler) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grant(Object[] args, Object result, Method method, Object originBean) {
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package tech.powerjob.server.auth.interceptor.gp;
|
||||
package tech.powerjob.server.auth.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -48,7 +48,7 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor {
|
||||
// 尝试直接解析登陆
|
||||
final Optional<PowerJobUser> loginUserOpt = powerJobLoginService.ifLogin(request);
|
||||
|
||||
// 未登录前先使用302重定向到登录页面
|
||||
// 未登录前先使用302重定向到登录页面 TODO: 前端登录还是服务端直接跳转有待考虑
|
||||
if (!loginUserOpt.isPresent()) {
|
||||
response.setStatus(302);
|
||||
response.setHeader("location", request.getContextPath() + "/login");
|
||||
|
@ -1,18 +0,0 @@
|
||||
package tech.powerjob.server.auth.interceptor.dp;
|
||||
|
||||
import tech.powerjob.server.auth.Permission;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* NotUseDynamicPermission
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/9/3
|
||||
*/
|
||||
public class EmptyDynamicPermission implements DynamicPermission {
|
||||
@Override
|
||||
public Permission calculate(HttpServletRequest request, Object handler) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package tech.powerjob.server.auth.interceptor.gp;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* do nothing
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/11
|
||||
*/
|
||||
public class EmptyGrantPermissionPlugin implements GrantPermissionPlugin {
|
||||
@Override
|
||||
public void grant(Object[] args, Object result, Method method, Object originBean) {
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package tech.powerjob.server.auth.service.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 javax.servlet.http.HttpServletRequest;
|
||||
@ -22,4 +24,14 @@ public interface PowerJobPermissionService {
|
||||
* @return true or false
|
||||
*/
|
||||
boolean hasPermission(HttpServletRequest request, Object handler, PowerJobUser user, ApiPermission apiPermission);
|
||||
|
||||
/**
|
||||
* 授予用户权限
|
||||
* @param roleScope 权限范围
|
||||
* @param target 权限目标
|
||||
* @param userId 用户ID
|
||||
* @param role 角色
|
||||
* @param extra 其他
|
||||
*/
|
||||
void grantPermission(RoleScope roleScope, Long target, Long userId, Role role, String extra);
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ 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.dp.DynamicPermission;
|
||||
import tech.powerjob.server.auth.interceptor.dp.EmptyDynamicPermission;
|
||||
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;
|
||||
@ -93,6 +93,23 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantPermission(RoleScope roleScope, Long target, Long userId, Role role, String extra) {
|
||||
|
||||
UserRoleDO userRoleDO = new UserRoleDO();
|
||||
userRoleDO.setGmtCreate(new Date());
|
||||
userRoleDO.setGmtModified(new Date());
|
||||
userRoleDO.setExtra(extra);
|
||||
|
||||
userRoleDO.setScope(roleScope.getV());
|
||||
userRoleDO.setTarget(target);
|
||||
userRoleDO.setUserId(userId);
|
||||
userRoleDO.setRole(role.getV());
|
||||
|
||||
userRoleRepository.saveAndFlush(userRoleDO);
|
||||
log.info("[PowerJobPermissionService] saveAndFlush userRole successfully: {}", userRoleDO);
|
||||
}
|
||||
|
||||
private boolean checkAppPermission(HttpServletRequest request, Permission requiredPermission, Multimap<Long, Role> appId2Role, Multimap<Long, Role> namespaceId2Role) {
|
||||
final String appIdStr = request.getHeader("appId");
|
||||
if (StringUtils.isEmpty(appIdStr)) {
|
||||
@ -144,12 +161,12 @@ public class PowerJobPermissionServiceImpl implements PowerJobPermissionService
|
||||
|
||||
|
||||
private static Permission parsePermission(HttpServletRequest request, Object handler, ApiPermission apiPermission) {
|
||||
Class<? extends DynamicPermission> dynamicPermissionPlugin = apiPermission.dynamicPermissionPlugin();
|
||||
if (EmptyDynamicPermission.class.equals(dynamicPermissionPlugin)) {
|
||||
Class<? extends DynamicPermissionPlugin> dynamicPermissionPlugin = apiPermission.dynamicPermissionPlugin();
|
||||
if (EmptyPlugin.class.equals(dynamicPermissionPlugin)) {
|
||||
return apiPermission.requiredPermission();
|
||||
}
|
||||
try {
|
||||
DynamicPermission dynamicPermission = dynamicPermissionPlugin.getDeclaredConstructor().newInstance();
|
||||
DynamicPermissionPlugin dynamicPermission = dynamicPermissionPlugin.getDeclaredConstructor().newInstance();
|
||||
return dynamicPermission.calculate(request, handler);
|
||||
} catch (Throwable t) {
|
||||
log.error("[PowerJobAuthService] process dynamicPermissionPlugin failed!", t);
|
||||
|
@ -39,6 +39,12 @@ public class NamespaceDO {
|
||||
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 部门,组织架构相关属性。
|
||||
* 预留数据库字段方便基于组织架构二次开发
|
||||
*/
|
||||
private String dept;
|
||||
|
||||
/**
|
||||
* 标签,扩展性之王,多值逗号分割
|
||||
*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tech.powerjob.server.persistence.remote.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import tech.powerjob.server.persistence.remote.model.NamespaceDO;
|
||||
|
||||
import java.util.Optional;
|
||||
@ -11,7 +12,7 @@ import java.util.Optional;
|
||||
* @author tjq
|
||||
* @since 2023/9/3
|
||||
*/
|
||||
public interface NamespaceRepository extends JpaRepository<NamespaceDO, Long> {
|
||||
public interface NamespaceRepository extends JpaRepository<NamespaceDO, Long>, JpaSpecificationExecutor<NamespaceDO> {
|
||||
|
||||
Optional<NamespaceDO> findByCode(String code);
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
package tech.powerjob.server.auth.interceptor.dp;
|
||||
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.interceptor.DynamicPermissionPlugin;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
@ -16,7 +17,7 @@ import java.util.Map;
|
||||
* @since 2023/9/3
|
||||
*/
|
||||
@Slf4j
|
||||
public class ModifyOrCreateDynamicPermission implements DynamicPermission {
|
||||
public class ModifyOrCreateDynamicPermission implements DynamicPermissionPlugin {
|
||||
@Override
|
||||
public Permission calculate(HttpServletRequest request, Object handler) {
|
||||
|
||||
@ -36,7 +37,7 @@ public class ModifyOrCreateDynamicPermission implements DynamicPermission {
|
||||
|
||||
return Permission.WRITE;
|
||||
} catch (Exception e) {
|
||||
log.error("[ModifyOrCreateDynamicPermission] check permission failed, please fix the bug!!!");
|
||||
log.error("[ModifyOrCreateDynamicPermission] check permission failed, please fix the bug!!!", e);
|
||||
}
|
||||
|
||||
// 异常情况先放行,不影响功能使用,后续修复 BUG
|
@ -1,4 +1,4 @@
|
||||
package tech.powerjob.server.auth.interceptor.gp;
|
||||
package tech.powerjob.server.auth.gp;
|
||||
|
||||
import tech.powerjob.server.auth.RoleScope;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package tech.powerjob.server.auth.interceptor.gp;
|
||||
package tech.powerjob.server.auth.gp;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
@ -8,6 +8,7 @@ import tech.powerjob.server.auth.LoginUserHolder;
|
||||
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.common.utils.SpringUtils;
|
||||
import tech.powerjob.server.persistence.remote.model.UserRoleDO;
|
||||
import tech.powerjob.server.persistence.remote.repository.UserRoleRepository;
|
@ -1,4 +1,4 @@
|
||||
package tech.powerjob.server.auth.interceptor.gp;
|
||||
package tech.powerjob.server.auth.gp;
|
||||
|
||||
import tech.powerjob.server.auth.RoleScope;
|
||||
|
@ -1,7 +1,5 @@
|
||||
package tech.powerjob.server.web;
|
||||
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
@ -10,6 +8,8 @@ import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
|
||||
/**
|
||||
* 统一处理 web 层异常信息
|
||||
@ -25,8 +25,13 @@ public class ControllerExceptionHandler {
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResultDTO<Void> exceptionHandler(Exception e) {
|
||||
|
||||
ResultDTO<Void> ret = ResultDTO.failed(ExceptionUtils.getMessage(e));
|
||||
|
||||
// 不是所有异常都需要打印完整堆栈,后续可以定义内部的Exception,便于判断
|
||||
if (e instanceof IllegalArgumentException || e instanceof PowerJobException) {
|
||||
if (e instanceof PowerJobException) {
|
||||
ret.setCode(((PowerJobException) e).getCode());
|
||||
log.warn("[ControllerException] PowerJobException, message is {}.", ExceptionUtils.getMessage(e));
|
||||
} else if (e instanceof IllegalArgumentException) {
|
||||
log.warn("[ControllerException] http request failed, message is {}.", e.getMessage());
|
||||
} else if (e instanceof HttpMessageNotReadableException || e instanceof MethodArgumentTypeMismatchException) {
|
||||
log.warn("[ControllerException] invalid http request params, exception is {}.", e.getMessage());
|
||||
@ -35,6 +40,7 @@ public class ControllerExceptionHandler {
|
||||
} else {
|
||||
log.error("[ControllerException] http request failed.", e);
|
||||
}
|
||||
return ResultDTO.failed(ExceptionUtils.getMessage(e));
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,26 @@
|
||||
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.server.auth.PowerJobUser;
|
||||
import tech.powerjob.common.serialize.JsonUtils;
|
||||
import tech.powerjob.server.auth.*;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -27,6 +35,8 @@ public class AuthController {
|
||||
|
||||
@Resource
|
||||
private PowerJobLoginService powerJobLoginService;
|
||||
@Resource
|
||||
private PowerJobPermissionService powerJobPermissionService;
|
||||
|
||||
@GetMapping("/supportLoginTypes")
|
||||
public ResultDTO<List<LoginTypeInfo>> listSupportLoginTypes() {
|
||||
@ -90,4 +100,34 @@ public class AuthController {
|
||||
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<Void> 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<Void> 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<String, Object> extraInfo = Maps.newHashMap();
|
||||
extraInfo.put("grantor", LoginUserHolder.getUserName());
|
||||
String extra = JsonUtils.toJSONString(extraInfo);
|
||||
|
||||
powerJobPermissionService.grantPermission(roleScope, grantPermissionRequest.getTargetId(), uid, role, extra);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,43 @@
|
||||
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;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
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.interceptor.dp.ModifyOrCreateDynamicPermission;
|
||||
import tech.powerjob.server.auth.interceptor.gp.SaveNamespaceGrantPermissionPlugin;
|
||||
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.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 javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -35,6 +53,10 @@ public class NamespaceController {
|
||||
|
||||
@Resource
|
||||
private NamespaceRepository namespaceRepository;
|
||||
@Resource
|
||||
private UserInfoRepository userInfoRepository;
|
||||
@Resource
|
||||
private UserRoleRepository userRoleRepository;
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping("/save")
|
||||
@ -53,9 +75,11 @@ public class NamespaceController {
|
||||
namespaceDO.setCode(req.getCode());
|
||||
// 创建时生成 token
|
||||
namespaceDO.setToken(UUID.randomUUID().toString());
|
||||
namespaceDO.setCreator(LoginUserHolder.getUserName());
|
||||
|
||||
} else {
|
||||
namespaceDO = fetchById(id);
|
||||
namespaceDO.setModifier(LoginUserHolder.getUserName());
|
||||
}
|
||||
|
||||
// 拷贝通用变更属性(code 不允许更改)
|
||||
@ -69,9 +93,69 @@ public class NamespaceController {
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
public ResultDTO<List<NamespaceBaseVO>> listNamespace(@RequestBody QueryNamespaceRequest queryNamespaceRequest) {
|
||||
List<NamespaceDO> allDos = namespaceRepository.findAll();
|
||||
return ResultDTO.success(allDos.stream().map(NamespaceConverter::do2BaseVo).collect(Collectors.toList()));
|
||||
public ResultDTO<PageResult<NamespaceBaseVO>> listNamespace(@RequestBody QueryNamespaceRequest queryNamespaceRequest) {
|
||||
|
||||
String codeLike = queryNamespaceRequest.getCodeLike();
|
||||
String nameLike = queryNamespaceRequest.getNameLike();
|
||||
String tagLike = queryNamespaceRequest.getTagLike();
|
||||
|
||||
Pageable pageable = PageRequest.of(queryNamespaceRequest.getIndex(), queryNamespaceRequest.getPageSize());
|
||||
Specification<NamespaceDO> specification = (root, query, cb) -> {
|
||||
|
||||
List<Predicate> predicates = Lists.newArrayList();
|
||||
|
||||
if (StringUtils.isNotEmpty(codeLike)) {
|
||||
predicates.add(cb.like(root.get("code"), QueryConvertUtils.convertLikeParams(codeLike)));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(nameLike)) {
|
||||
predicates.add(cb.like(root.get("name"), QueryConvertUtils.convertLikeParams(nameLike)));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(tagLike)) {
|
||||
predicates.add(cb.like(root.get("tags"), QueryConvertUtils.convertLikeParams(tagLike)));
|
||||
}
|
||||
|
||||
if (predicates.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return query.where(predicates.toArray(new Predicate[0])).getRestriction();
|
||||
};
|
||||
|
||||
Page<NamespaceDO> namespacePageResult = namespaceRepository.findAll(specification, pageable);
|
||||
|
||||
PageResult<NamespaceBaseVO> ret = new PageResult<>(namespacePageResult);
|
||||
ret.setData(namespacePageResult.get().map(NamespaceConverter::do2BaseVo).collect(Collectors.toList()));
|
||||
|
||||
return ResultDTO.success(ret);
|
||||
}
|
||||
|
||||
@GetMapping("/detail")
|
||||
@ApiPermission(name = "Namespace-GetDetail", roleScope = RoleScope.NAMESPACE, requiredPermission = Permission.READ)
|
||||
public ResultDTO<NamespaceDetailVO> queryNamespaceDetail(Long id) {
|
||||
|
||||
NamespaceDO namespaceDO = fetchById(id);
|
||||
NamespaceDetailVO namespaceDetailVO = new NamespaceDetailVO();
|
||||
|
||||
// 拷贝基础字段
|
||||
NamespaceBaseVO namespaceBaseVO = NamespaceConverter.do2BaseVo(namespaceDO);
|
||||
BeanUtils.copyProperties(namespaceBaseVO, namespaceDetailVO);
|
||||
|
||||
// 处理 token
|
||||
namespaceDetailVO.setToken(namespaceDO.getToken());
|
||||
|
||||
// 处理权限视图
|
||||
Map<String, List<UserBaseVO>> privilegedUsers = Maps.newHashMap();
|
||||
namespaceDetailVO.setPrivilegedUsers(privilegedUsers);
|
||||
List<UserRoleDO> permissionUserList = userRoleRepository.findAllByScopeAndTarget(RoleScope.NAMESPACE.getV(), namespaceDO.getId());
|
||||
permissionUserList.forEach(r -> {
|
||||
Role role = Role.of(r.getRole());
|
||||
List<UserBaseVO> userBaseVOList = privilegedUsers.computeIfAbsent(role.name(), ignore -> Lists.newArrayList());
|
||||
|
||||
Optional<UserInfoDO> userInfoDoOpt = userInfoRepository.findById(r.getUserId());
|
||||
userInfoDoOpt.ifPresent(userInfoDO -> userBaseVOList.add(UserConverter.do2BaseVo(userInfoDO)));
|
||||
});
|
||||
|
||||
return ResultDTO.success(namespaceDetailVO);
|
||||
}
|
||||
|
||||
private NamespaceDO fetchById(Long id) {
|
||||
|
@ -1,18 +1,17 @@
|
||||
package tech.powerjob.server.web.controller;
|
||||
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.server.core.service.UserService;
|
||||
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
||||
import tech.powerjob.server.core.service.UserService;
|
||||
import tech.powerjob.server.web.converter.UserConverter;
|
||||
import tech.powerjob.server.web.request.ModifyUserInfoRequest;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.powerjob.server.web.response.UserBaseVO;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
@ -27,7 +26,6 @@ import java.util.stream.Collectors;
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserInfoController {
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
@Resource
|
||||
@ -42,7 +40,7 @@ public class UserInfoController {
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
public ResultDTO<List<UserItemVO>> list(@RequestParam(required = false) String name) {
|
||||
public ResultDTO<List<UserBaseVO>> list(@RequestParam(required = false) String name) {
|
||||
|
||||
List<UserInfoDO> result;
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
@ -53,18 +51,10 @@ public class UserInfoController {
|
||||
return ResultDTO.success(convert(result));
|
||||
}
|
||||
|
||||
private static List<UserItemVO> convert(List<UserInfoDO> data) {
|
||||
private static List<UserBaseVO> convert(List<UserInfoDO> data) {
|
||||
if (CollectionUtils.isEmpty(data)) {
|
||||
return Lists.newLinkedList();
|
||||
}
|
||||
return data.stream().map(x -> new UserItemVO(x.getId(), x.getUsername())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static final class UserItemVO {
|
||||
private Long id;
|
||||
private String username;
|
||||
return data.stream().map(UserConverter::do2BaseVo).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package tech.powerjob.server.web.converter;
|
||||
|
||||
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||
import tech.powerjob.server.web.response.UserBaseVO;
|
||||
|
||||
/**
|
||||
* UserConverter
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/9/4
|
||||
*/
|
||||
public class UserConverter {
|
||||
|
||||
public static UserBaseVO do2BaseVo(UserInfoDO x) {
|
||||
UserBaseVO userBaseVO = new UserBaseVO();
|
||||
userBaseVO.setId(x.getId());
|
||||
userBaseVO.setUsername(x.getUsername());
|
||||
userBaseVO.setNick(x.getNick());
|
||||
return userBaseVO;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package tech.powerjob.server.web.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 授权请求
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/12
|
||||
*/
|
||||
@Data
|
||||
public class GrantPermissionRequest implements Serializable {
|
||||
|
||||
/**
|
||||
* 目标ID
|
||||
*/
|
||||
private Long targetId;
|
||||
|
||||
/**
|
||||
* 授予的角色
|
||||
*/
|
||||
private Integer role;
|
||||
|
||||
/**
|
||||
* 授予的用户IDS
|
||||
*/
|
||||
private List<Long> userIds;
|
||||
}
|
@ -26,6 +26,8 @@ public class ModifyNamespaceRequest {
|
||||
*/
|
||||
private String name;
|
||||
|
||||
private String dept;
|
||||
|
||||
/**
|
||||
* 标签,扩展性之王,多值逗号分割
|
||||
*/
|
||||
|
@ -29,6 +29,7 @@ public class QueryAppInfoRequest {
|
||||
*/
|
||||
private Boolean showMyRelated;
|
||||
|
||||
/* ****************** 分页参数 ****************** */
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
|
@ -14,10 +14,22 @@ public class QueryNamespaceRequest {
|
||||
/**
|
||||
* code 模糊查询
|
||||
*/
|
||||
private String code;
|
||||
private String codeLike;
|
||||
|
||||
/**
|
||||
* 名称模糊查询
|
||||
*/
|
||||
private String name;
|
||||
private String nameLike;
|
||||
|
||||
private String tagLike;
|
||||
|
||||
/* ****************** 分页参数 ****************** */
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
private Integer index = 0;
|
||||
/**
|
||||
* 页大小
|
||||
*/
|
||||
private Integer pageSize = 10;
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ public class NamespaceBaseVO implements Serializable {
|
||||
*/
|
||||
private String name;
|
||||
|
||||
private String dept;
|
||||
private String tags;
|
||||
|
||||
private Integer status;
|
||||
private String statusStr;
|
||||
|
||||
|
@ -0,0 +1,29 @@
|
||||
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<String, List<UserBaseVO>> privilegedUsers;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package tech.powerjob.server.web.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 用户基础信息
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/9/3
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class UserBaseVO {
|
||||
private Long id;
|
||||
private String username;
|
||||
private String nick;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user