feat: 为访问令牌增加名称

- 支持创建和编辑访问令牌名称

- 在列表首列展示名称并兼容历史数据
This commit is contained in:
2026-08-07 12:55:04 +08:00
parent d244a0404d
commit 13dec6c216
8 changed files with 220 additions and 14 deletions

View File

@@ -43,6 +43,17 @@ import java.util.Set;
@RestController
@RequestMapping("/api/v1/sysApiKey")
public class SysApiKeyController extends BaseCurdController<SysApiKeyService, SysApiKey> {
/**
* 访问令牌名称最大长度。
*/
private static final int API_KEY_NAME_MAX_LENGTH = 100;
/**
* 兼容旧客户端时使用的默认名称前缀。
*/
private static final String DEFAULT_API_KEY_NAME_PREFIX = "访问令牌-";
public SysApiKeyController(SysApiKeyService service) {
super(service);
}
@@ -56,13 +67,19 @@ public class SysApiKeyController extends BaseCurdController<SysApiKeyService, Sy
/**
* 添加(保存)数据
*
* @param name 访问令牌名称
* @return {@code Result.errorCode == 0} 添加成功,否则添加失败
*/
@PostMapping("/key/save")
@SaCheckPermission("/api/v1/sysApiKey/save")
public Result<PkVo> save() {
public Result<PkVo> save(@JsonBody(value = "name", required = false) String name) {
String apiKey = IdUtil.generateUUID();
String normalizedName = normalizeCreateName(name, apiKey);
if (normalizedName.length() > API_KEY_NAME_MAX_LENGTH) {
return Result.fail("访问令牌名称不能超过100个字符", null);
}
SysApiKey entity = new SysApiKey();
entity.setName(normalizedName);
entity.setApiKey(apiKey);
entity.setCreated(new Date());
entity.setStatus(1);
@@ -103,6 +120,10 @@ public class SysApiKeyController extends BaseCurdController<SysApiKeyService, Sy
if (entity == null || entity.getId() == null) {
return Result.fail("访问令牌 ID 不能为空");
}
Result<?> nameValidationResult = normalizeAndValidateUpdateName(entity);
if (nameValidationResult != null) {
return nameValidationResult;
}
if (!hasPersistentUpdateFields(entity) && !hasPermissionUpdateFields(entity)) {
return Result.fail("没有可更新的访问令牌字段");
}
@@ -230,7 +251,8 @@ public class SysApiKeyController extends BaseCurdController<SysApiKeyService, Sy
* @return 是否需要更新访问令牌主表
*/
private boolean hasPersistentUpdateFields(SysApiKey entity) {
return entity.getApiKey() != null
return entity.getName() != null
|| entity.getApiKey() != null
|| entity.getCreated() != null
|| entity.getStatus() != null
|| entity.getDeptId() != null
@@ -251,4 +273,42 @@ public class SysApiKeyController extends BaseCurdController<SysApiKeyService, Sy
|| hasNewKnowledgePermissionFields(entity)
|| entity.getWorkflowApiEnabled() != null;
}
/**
* 标准化新建访问令牌的名称。
*
* <p>未传名称时生成可识别的兼容名称,避免旧客户端在升级期间创建空名称记录。</p>
*
* @param name 客户端提交的名称
* @param apiKey 新生成的访问令牌
* @return 标准化后的名称
*/
private String normalizeCreateName(String name, String apiKey) {
if (name != null && !name.trim().isEmpty()) {
return name.trim();
}
int suffixStart = Math.max(0, apiKey.length() - 6);
return DEFAULT_API_KEY_NAME_PREFIX + apiKey.substring(suffixStart);
}
/**
* 标准化并校验更新请求中的访问令牌名称。
*
* @param entity 待更新的访问令牌
* @return 校验失败结果;无需校验或校验成功时返回 {@code null}
*/
private Result<?> normalizeAndValidateUpdateName(SysApiKey entity) {
if (entity.getName() == null) {
return null;
}
String normalizedName = entity.getName().trim();
if (normalizedName.isEmpty()) {
return Result.fail("访问令牌名称不能为空");
}
if (normalizedName.length() > API_KEY_NAME_MAX_LENGTH) {
return Result.fail("访问令牌名称不能超过100个字符");
}
entity.setName(normalizedName);
return null;
}
}

View File

@@ -79,6 +79,50 @@ public class SysApiKeyControllerTest {
verify(knowledgePermissionService).replaceApiPermissions(apiKeyId, true, true, true);
}
/**
* 验证名称可以单独更新,并在持久化前移除首尾空格。
*/
@Test
public void updateShouldPersistTrimmedNameOnly() {
BigInteger apiKeyId = BigInteger.valueOf(103);
SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
KnowledgeSharePermissionService knowledgePermissionService =
mock(KnowledgeSharePermissionService.class);
SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
SysApiKey existing = new SysApiKey();
existing.setId(apiKeyId);
when(apiKeyService.getById(apiKeyId)).thenReturn(existing);
SysApiKey request = new SysApiKey();
request.setId(apiKeyId);
request.setName(" 生产环境调用 ");
Result<?> result = controller.update(request);
assertEquals(result.getErrorCode(), 0);
assertEquals(request.getName(), "生产环境调用");
verify(apiKeyService).updateById(request);
}
/**
* 验证空白名称会被拒绝,避免覆盖为无意义内容。
*/
@Test
public void updateShouldRejectBlankName() {
SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
KnowledgeSharePermissionService knowledgePermissionService =
mock(KnowledgeSharePermissionService.class);
SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
SysApiKey request = new SysApiKey();
request.setId(BigInteger.valueOf(104));
request.setName(" ");
Result<?> result = controller.update(request);
assertNotEquals(result.getErrorCode(), 0);
verifyNoInteractions(apiKeyService, knowledgePermissionService);
}
/**
* 验证新版知识库权限缺少字段时拒绝更新,避免遗漏字段被隐式关闭。
*/