fix: 修复工作流公共 API 调用问题

- 限制远程文档仅访问公网地址并校验重定向目标

- 统一访问令牌 401/403 与过期执行状态 404 语义

- 校正节点查询参数和工作流状态文档
This commit is contained in:
2026-07-31 11:27:37 +08:00
parent 1cbee6b018
commit 41b056b7e3
12 changed files with 953 additions and 33 deletions

View File

@@ -50,7 +50,7 @@ public class SysApiKeyServiceImpl extends ServiceImpl<SysApiKeyMapper, SysApiKey
wm.in(SysApiKeyResourceMapping::getApiKeyResourceId, resourceIds);
long count = mappingService.count(wm);
if (count == 0) {
throw new BusinessException("该apiKey无权限访问该接口");
throw new BusinessException(403, 403, "该apiKey无权限访问该接口");
}
}
@@ -70,11 +70,11 @@ public class SysApiKeyServiceImpl extends ServiceImpl<SysApiKeyMapper, SysApiKey
QueryWrapper w = QueryWrapper.create();
w.eq(SysApiKey::getApiKey, apiKey);
SysApiKey one = getOne(w);
if (one == null || one.getStatus() == 0) {
throw new BusinessException("apiKey 不存在或已禁用");
if (one == null || !Integer.valueOf(1).equals(one.getStatus())) {
throw new BusinessException(401, 401, "apiKey 不存在或已禁用");
}
if (one.getExpiredAt() != null && one.getExpiredAt().getTime() < new Date().getTime()) {
throw new BusinessException("apiKey 已过期");
throw new BusinessException(401, 401, "apiKey 已过期");
}
return one;
}
@@ -107,7 +107,7 @@ public class SysApiKeyServiceImpl extends ServiceImpl<SysApiKeyMapper, SysApiKey
globalScopeWrapper.isNull(SysApiKeyResourceMapping::getResourceTargetId);
globalScopeWrapper.eq(SysApiKeyResourceMapping::getActionScope, actionScope);
if (mappingService.count(globalScopeWrapper) == 0) {
throw new BusinessException("该apiKey无权限访问当前资源");
throw new BusinessException(403, 403, "该apiKey无权限访问当前资源");
}
}

View File

@@ -0,0 +1,106 @@
package tech.easyflow.system.service.impl;
import com.mybatisflex.core.query.QueryWrapper;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.entity.SysApiKey;
import java.util.Date;
/**
* API Key 认证状态错误语义测试。
*/
public class SysApiKeyAuthenticationStatusTest {
/**
* 验证不存在的 API Key 使用 HTTP 401 语义。
*/
@Test
public void shouldReturnUnauthorizedWhenApiKeyMissing() {
TestSysApiKeyService service = new TestSysApiKeyService(null);
BusinessException error = expectBusinessException(
() -> service.getSysApiKey("missing"));
Assert.assertEquals(401, error.getHttpStatus());
Assert.assertEquals(401, error.getErrorCode());
}
/**
* 验证状态缺失的 API Key 按禁用处理并返回 HTTP 401。
*/
@Test
public void shouldReturnUnauthorizedWhenApiKeyStatusMissing() {
SysApiKey apiKey = new SysApiKey();
TestSysApiKeyService service = new TestSysApiKeyService(apiKey);
BusinessException error = expectBusinessException(
() -> service.getSysApiKey("status-missing"));
Assert.assertEquals(401, error.getHttpStatus());
Assert.assertEquals(401, error.getErrorCode());
}
/**
* 验证过期的 API Key 使用 HTTP 401 语义。
*/
@Test
public void shouldReturnUnauthorizedWhenApiKeyExpired() {
SysApiKey apiKey = new SysApiKey();
apiKey.setStatus(1);
apiKey.setExpiredAt(new Date(System.currentTimeMillis() - 1_000L));
TestSysApiKeyService service = new TestSysApiKeyService(apiKey);
BusinessException error = expectBusinessException(
() -> service.getSysApiKey("expired"));
Assert.assertEquals(401, error.getHttpStatus());
Assert.assertEquals(401, error.getErrorCode());
}
/**
* 执行调用并返回预期业务异常。
*
* @param action 待执行调用
* @return 捕获的业务异常
*/
private BusinessException expectBusinessException(Runnable action) {
try {
action.run();
Assert.fail("expected BusinessException");
return null;
} catch (BusinessException error) {
return error;
}
}
/**
* 固定返回 API Key 的测试服务。
*/
private static final class TestSysApiKeyService
extends SysApiKeyServiceImpl {
private final SysApiKey apiKey;
/**
* 创建测试服务。
*
* @param apiKey 查询时返回的 API Key
*/
private TestSysApiKeyService(SysApiKey apiKey) {
this.apiKey = apiKey;
}
/**
* 返回预设 API Key。
*
* @param queryWrapper 查询条件
* @return 预设 API Key
*/
@Override
public SysApiKey getOne(QueryWrapper queryWrapper) {
return apiKey;
}
}
}