refactor: CheckOwner 支持验证中间表

This commit is contained in:
CaptainB 2024-06-07 10:57:14 +08:00 committed by 刘瑞斌
parent 8e52dd5c8d
commit 631f8c5f2c
4 changed files with 74 additions and 3 deletions

View File

@ -7,6 +7,8 @@ import java.util.List;
public interface ExtCheckOwnerMapper { public interface ExtCheckOwnerMapper {
boolean checkoutOwner(@Param("table") String resourceType, @Param("userId") String userId, @Param("ids") List<String> ids); boolean checkoutOwner(@Param("table") String resourceType, @Param("userId") String userId, @Param("ids") List<String> ids);
boolean checkoutRelationOwner(@Param("table") String resourceType, @Param("relationTable") String relationType, @Param("userId") String userId, @Param("ids") List<String> ids);
boolean checkoutOrganizationOwner(@Param("table") String resourceType, @Param("userId") String userId, @Param("ids") List<String> ids); boolean checkoutOrganizationOwner(@Param("table") String resourceType, @Param("userId") String userId, @Param("ids") List<String> ids);
boolean checkoutOrganization(@Param("userId") String userId, @Param("ids") List<String> ids); boolean checkoutOrganization(@Param("userId") String userId, @Param("ids") List<String> ids);

View File

@ -13,6 +13,19 @@
AND user_id = #{userId} AND user_id = #{userId}
</select> </select>
<select id="checkoutRelationOwner" resultType="boolean">
SELECT count(1) > 0
FROM user_role_relation
WHERE source_id IN (SELECT project_id
FROM ${table} JOIN ${relationTable} ON ${table}.id = ${relationTable}.${table}_id
JOIN project ON ${table}.project_id = project.id AND project.enable = TRUE
WHERE ${table}.id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>)
AND user_id = #{userId}
</select>
<select id="checkoutOrganizationOwner" resultType="boolean"> <select id="checkoutOrganizationOwner" resultType="boolean">
SELECT count(1) > 0 SELECT count(1) > 0
FROM user_role_relation FROM user_role_relation

View File

@ -9,4 +9,6 @@ public @interface CheckOwner {
String resourceId(); String resourceId();
String resourceType(); String resourceType();
String relationType() default "";
} }

View File

@ -7,8 +7,13 @@ import io.metersphere.sdk.util.Translator;
import io.metersphere.system.mapper.ExtCheckOwnerMapper; import io.metersphere.system.mapper.ExtCheckOwnerMapper;
import io.metersphere.system.utils.SessionUtils; import io.metersphere.system.utils.SessionUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.util.WebUtils;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
@ -20,6 +25,8 @@ import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import java.util.List;
@ -42,6 +49,17 @@ public class CheckOwnerAspect {
@Before("pointcut()") @Before("pointcut()")
public void before(JoinPoint joinPoint) { public void before(JoinPoint joinPoint) {
// apikey 过来的请求
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
if (ApiKeyHandler.isApiKeyCall(request) && !SecurityUtils.getSubject().isAuthenticated()) {
String userId = ApiKeyHandler.getUser(WebUtils.toHttp(request));
SecurityUtils.getSubject().login(new UsernamePasswordToken(userId, "no_pass"));
}
}
//从切面织入点处通过反射机制获取织入点处的方法 //从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法 //获取切入点所在的方法
@ -67,13 +85,23 @@ public class CheckOwnerAspect {
String resourceId = checkOwner.resourceId(); String resourceId = checkOwner.resourceId();
String resourceType = checkOwner.resourceType(); String resourceType = checkOwner.resourceType();
String relationType = checkOwner.relationType();
Expression titleExp = parser.parseExpression(resourceId); Expression titleExp = parser.parseExpression(resourceId);
Object v = titleExp.getValue(context, Object.class); Object v = titleExp.getValue(context, Object.class);
// 归属组织的资源
if (orgResources.contains(resourceType)) { if (orgResources.contains(resourceType)) {
handleOrganizationResource(v, resourceType); handleOrganizationResource(v, resourceType);
} else if (StringUtils.equals(resourceType, "organization")) { }
// 组织自身
else if (StringUtils.equals(resourceType, "organization")) {
handleOrganization(v); handleOrganization(v);
} else { }
// 中间表
else if (StringUtils.isNotBlank(relationType)) {
handleProjectResource(v, resourceType, relationType);
}
// 归属项目的资源
else {
handleProjectResource(v, resourceType); handleProjectResource(v, resourceType);
} }
} }
@ -104,6 +132,20 @@ public class CheckOwnerAspect {
} }
} }
private void handleProjectResource(Object v, String resourceType, String relationType) {
if (v instanceof String id) {
if (!extCheckOwnerMapper.checkoutRelationOwner(resourceType, relationType, SessionUtils.getUserId(), List.of(id))) {
throw new MSException(Translator.get("check_owner_case"));
}
}
if (v instanceof List ids) {
if (!extCheckOwnerMapper.checkoutRelationOwner(resourceType, relationType, SessionUtils.getUserId(), ids)) {
throw new MSException(Translator.get("check_owner_case"));
}
}
}
private void handleOrganizationResource(Object v, String resourceType) { private void handleOrganizationResource(Object v, String resourceType) {
if (v instanceof String id) { if (v instanceof String id) {
if (!extCheckOwnerMapper.checkoutOrganizationOwner(resourceType, SessionUtils.getUserId(), List.of(id))) { if (!extCheckOwnerMapper.checkoutOrganizationOwner(resourceType, SessionUtils.getUserId(), List.of(id))) {
@ -117,4 +159,16 @@ public class CheckOwnerAspect {
} }
} }
@After("pointcut()")
public void after() {
// apikey 过来的请求
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
// apikey 退出
if (ApiKeyHandler.isApiKeyCall(WebUtils.toHttp(request)) && SecurityUtils.getSubject().isAuthenticated()) {
SecurityUtils.getSubject().logout();
}
}
}
} }