refactor(系统设置): 优化apiKey
This commit is contained in:
parent
4f5463c01a
commit
28b759dedb
|
@ -0,0 +1,9 @@
|
||||||
|
-- set innodb lock wait timeout
|
||||||
|
SET SESSION innodb_lock_wait_timeout = 7200;
|
||||||
|
|
||||||
|
ALTER TABLE user_key MODIFY COLUMN description VARCHAR(1000);
|
||||||
|
|
||||||
|
-- set innodb lock wait timeout to default
|
||||||
|
SET SESSION innodb_lock_wait_timeout = DEFAULT;
|
||||||
|
|
||||||
|
|
|
@ -529,4 +529,6 @@ relate_source_type_not_blank=关联资源类型不能为空
|
||||||
api_import_schedule=接口定义-定时导入任务
|
api_import_schedule=接口定义-定时导入任务
|
||||||
project.description.length_range=项目描述长度必须在{min}和{max}之间
|
project.description.length_range=项目描述长度必须在{min}和{max}之间
|
||||||
api_test_environment_datasource_connect_failed=数据源连接失败
|
api_test_environment_datasource_connect_failed=数据源连接失败
|
||||||
ms_url_not_available=资源池无法访问当前站点
|
ms_url_not_available=资源池无法访问当前站点
|
||||||
|
api_key_not_exist=ApiKey不存在
|
||||||
|
current_user_can_not_operation_api_key=当前用户无操作该ApiKey的权限
|
||||||
|
|
|
@ -568,3 +568,5 @@ api_test_environment_datasource_connect_failed=Data source connection failed
|
||||||
permission.api_definition.delete_and_recover=Delete/Recover
|
permission.api_definition.delete_and_recover=Delete/Recover
|
||||||
permission.service_integration.reset=Reset
|
permission.service_integration.reset=Reset
|
||||||
ms_url_not_available=The resource pool cannot access the current site
|
ms_url_not_available=The resource pool cannot access the current site
|
||||||
|
api_key_not_exist=API key does not exist
|
||||||
|
current_user_can_not_operation_api_key=The current user cannot operate the API key
|
||||||
|
|
|
@ -564,4 +564,6 @@ api_test_environment_datasource_connect_failed=数据源连接失败
|
||||||
|
|
||||||
permission.api_definition.delete_and_recover=删除/恢复
|
permission.api_definition.delete_and_recover=删除/恢复
|
||||||
permission.service_integration.reset=重置
|
permission.service_integration.reset=重置
|
||||||
ms_url_not_available=资源池无法访问当前站点
|
ms_url_not_available=资源池无法访问当前站点
|
||||||
|
api_key_not_exist=ApiKey不存在
|
||||||
|
current_user_can_not_operation_api_key=当前用户无操作该ApiKey的权限
|
|
@ -564,4 +564,6 @@ project.description.length_range=項目描述長度必須在{min}和{max}之間
|
||||||
|
|
||||||
permission.api_definition.delete_and_recover=刪除/恢復
|
permission.api_definition.delete_and_recover=刪除/恢復
|
||||||
permission.service_integration.reset=重置
|
permission.service_integration.reset=重置
|
||||||
ms_url_not_available=資源池無法訪問當前站點
|
ms_url_not_available=資源池無法訪問當前站點
|
||||||
|
api_key_not_exist=ApiKey不存在
|
||||||
|
current_user_can_not_operation_api_key=當前用戶無法操作ApiKey
|
|
@ -54,6 +54,7 @@ public class UserApiKeysController {
|
||||||
@Operation(summary = "系统设置-个人中心-我的设置-Api Keys-删除Api Keys")
|
@Operation(summary = "系统设置-个人中心-我的设置-Api Keys-删除Api Keys")
|
||||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = UserKeyLogService.class)
|
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = UserKeyLogService.class)
|
||||||
public void delete(@PathVariable String id) {
|
public void delete(@PathVariable String id) {
|
||||||
|
userKeyService.checkUserKeyOwner(id, SessionUtils.getUserId());
|
||||||
userKeyService.deleteUserKey(id);
|
userKeyService.deleteUserKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,22 +63,25 @@ public class UserApiKeysController {
|
||||||
@RequiresPermissions(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE)
|
@RequiresPermissions(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE)
|
||||||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = UserKeyLogService.class)
|
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = UserKeyLogService.class)
|
||||||
public void update(@Validated @RequestBody UserKeyDTO request) {
|
public void update(@Validated @RequestBody UserKeyDTO request) {
|
||||||
|
userKeyService.checkUserKeyOwner(request.getId(), SessionUtils.getUserId());
|
||||||
userKeyService.updateUserKey(request);
|
userKeyService.updateUserKey(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/enable/{id}")
|
@GetMapping("/enable/{id}")
|
||||||
@Operation(summary = "系统设置-个人中心-我的设置-Api Keys-开启Api Keys")
|
@Operation(summary = "系统设置-个人中心-我的设置-Api Keys-开启Api Keys")
|
||||||
@RequiresPermissions(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE)
|
@RequiresPermissions(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE)
|
||||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.enableLog(#id)", msClass = UserKeyLogService.class)
|
@Log(type = OperationLogType.UPDATE, expression = "#msClass.enableLog(#id)", msClass = UserKeyLogService.class)
|
||||||
public void enable(@PathVariable String id) {
|
public void enable(@PathVariable String id) {
|
||||||
|
userKeyService.checkUserKeyOwner(id, SessionUtils.getUserId());
|
||||||
userKeyService.enableUserKey(id);
|
userKeyService.enableUserKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/disable/{id}")
|
@GetMapping("/disable/{id}")
|
||||||
@Operation(summary = "系统设置-个人中心-我的设置-Api Keys-关闭Api Keys")
|
@Operation(summary = "系统设置-个人中心-我的设置-Api Keys-关闭Api Keys")
|
||||||
@RequiresPermissions(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE)
|
@RequiresPermissions(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE)
|
||||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.disableLog(#id)", msClass = UserKeyLogService.class)
|
@Log(type = OperationLogType.UPDATE, expression = "#msClass.disableLog(#id)", msClass = UserKeyLogService.class)
|
||||||
public void disabledUserKey(@PathVariable String id) {
|
public void disabledUserKey(@PathVariable String id) {
|
||||||
|
userKeyService.checkUserKeyOwner(id, SessionUtils.getUserId());
|
||||||
userKeyService.disableUserKey(id);
|
userKeyService.disableUserKey(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io.metersphere.system.mapper.UserKeyMapper;
|
||||||
import io.metersphere.system.uid.IDGenerator;
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
@ -81,10 +82,12 @@ public class UserKeyService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteUserKey(String id) {
|
public void deleteUserKey(String id) {
|
||||||
|
checkUserKey(id);
|
||||||
userKeyMapper.deleteByPrimaryKey(id);
|
userKeyMapper.deleteByPrimaryKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableUserKey(String id) {
|
public void enableUserKey(String id) {
|
||||||
|
checkUserKey(id);
|
||||||
UserKey userKeys = new UserKey();
|
UserKey userKeys = new UserKey();
|
||||||
userKeys.setId(id);
|
userKeys.setId(id);
|
||||||
userKeys.setEnable(true);
|
userKeys.setEnable(true);
|
||||||
|
@ -92,6 +95,7 @@ public class UserKeyService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableUserKey(String id) {
|
public void disableUserKey(String id) {
|
||||||
|
checkUserKey(id);
|
||||||
UserKey userKeys = new UserKey();
|
UserKey userKeys = new UserKey();
|
||||||
userKeys.setId(id);
|
userKeys.setId(id);
|
||||||
userKeys.setEnable(false);
|
userKeys.setEnable(false);
|
||||||
|
@ -109,18 +113,33 @@ public class UserKeyService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateUserKey(UserKeyDTO userKeyDTO) {
|
public void updateUserKey(UserKeyDTO userKeyDTO) {
|
||||||
UserKey userKeys = new UserKey();
|
UserKey userKey = checkUserKey(userKeyDTO.getId());
|
||||||
userKeys.setId(userKeyDTO.getId());
|
userKey.setId(userKeyDTO.getId());
|
||||||
userKeys.setForever(userKeyDTO.getForever());
|
userKey.setForever(userKeyDTO.getForever());
|
||||||
if (BooleanUtils.isFalse(userKeyDTO.getForever())) {
|
if (BooleanUtils.isFalse(userKeyDTO.getForever())) {
|
||||||
if (userKeyDTO.getExpireTime() == null) {
|
if (userKeyDTO.getExpireTime() == null) {
|
||||||
throw new MSException(Translator.get("expire_time_not_null"));
|
throw new MSException(Translator.get("expire_time_not_null"));
|
||||||
}
|
}
|
||||||
userKeys.setExpireTime(userKeyDTO.getExpireTime());
|
userKey.setExpireTime(userKeyDTO.getExpireTime());
|
||||||
} else {
|
} else {
|
||||||
userKeys.setExpireTime(null);
|
userKey.setExpireTime(null);
|
||||||
|
}
|
||||||
|
userKey.setDescription(userKeyDTO.getDescription());
|
||||||
|
userKeyMapper.updateByPrimaryKeySelective(userKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserKey checkUserKey(String id) {
|
||||||
|
UserKey userKey = userKeyMapper.selectByPrimaryKey(id);
|
||||||
|
if (userKey == null) {
|
||||||
|
throw new MSException(Translator.get("api_key_not_exist"));
|
||||||
|
}
|
||||||
|
return userKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkUserKeyOwner(String id, String userId) {
|
||||||
|
UserKey userKey = checkUserKey(id);
|
||||||
|
if (!StringUtils.equals(userKey.getCreateUser(), userId)) {
|
||||||
|
throw new MSException(Translator.get("current_user_can_not_operation_api_key"));
|
||||||
}
|
}
|
||||||
userKeys.setDescription(userKeyDTO.getDescription());
|
|
||||||
userKeyMapper.updateByPrimaryKeySelective(userKeys);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.system.controller;
|
package io.metersphere.system.controller;
|
||||||
|
|
||||||
|
import com.jayway.jsonpath.JsonPath;
|
||||||
import io.metersphere.sdk.constants.PermissionConstants;
|
import io.metersphere.sdk.constants.PermissionConstants;
|
||||||
import io.metersphere.sdk.constants.SessionConstants;
|
import io.metersphere.sdk.constants.SessionConstants;
|
||||||
import io.metersphere.sdk.util.CodingUtils;
|
import io.metersphere.sdk.util.CodingUtils;
|
||||||
|
@ -19,6 +20,8 @@ import org.junit.jupiter.api.*;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||||
|
@ -28,6 +31,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
@ -65,6 +69,9 @@ public class UserApiKeysControllerTests extends BaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1)
|
@Order(1)
|
||||||
|
@Sql(scripts = {"/dml/init_project.sql"},
|
||||||
|
config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED),
|
||||||
|
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
|
||||||
public void testAdd() throws Exception {
|
public void testAdd() throws Exception {
|
||||||
requestGet(ADD);
|
requestGet(ADD);
|
||||||
UserKeyExample userKeyExample = new UserKeyExample();
|
UserKeyExample userKeyExample = new UserKeyExample();
|
||||||
|
@ -108,6 +115,8 @@ public class UserApiKeysControllerTests extends BaseTest {
|
||||||
Assertions.assertEquals(4, userKeyMapper.countByExample(userKeyExample));
|
Assertions.assertEquals(4, userKeyMapper.countByExample(userKeyExample));
|
||||||
//校验日志
|
//校验日志
|
||||||
checkLog(list.get(0), OperationLogType.DELETE);
|
checkLog(list.get(0), OperationLogType.DELETE);
|
||||||
|
//处理不存在的
|
||||||
|
requestGet(String.format(DELETE, UUID.randomUUID().toString()), status().is5xxServerError());
|
||||||
//校验权限
|
//校验权限
|
||||||
requestGetPermissionTest(PermissionConstants.SYSTEM_PERSONAL_API_KEY_DELETE, DELETE);
|
requestGetPermissionTest(PermissionConstants.SYSTEM_PERSONAL_API_KEY_DELETE, DELETE);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +137,13 @@ public class UserApiKeysControllerTests extends BaseTest {
|
||||||
this.requestPost(UPDATE, userKeyDTO, status().is5xxServerError());
|
this.requestPost(UPDATE, userKeyDTO, status().is5xxServerError());
|
||||||
userKeyDTO.setExpireTime(System.currentTimeMillis() - 1000000);
|
userKeyDTO.setExpireTime(System.currentTimeMillis() - 1000000);
|
||||||
this.requestPost(UPDATE, userKeyDTO);
|
this.requestPost(UPDATE, userKeyDTO);
|
||||||
|
//描述为空
|
||||||
|
userKeyDTO.setDescription(null);
|
||||||
|
this.requestPost(UPDATE, userKeyDTO);
|
||||||
|
|
||||||
|
//校验不存在的
|
||||||
|
userKeyDTO.setId(UUID.randomUUID().toString());
|
||||||
|
this.requestPost(UPDATE, userKeyDTO, status().is5xxServerError());
|
||||||
//校验日志
|
//校验日志
|
||||||
checkLog(userKeyId, OperationLogType.UPDATE);
|
checkLog(userKeyId, OperationLogType.UPDATE);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +166,24 @@ public class UserApiKeysControllerTests extends BaseTest {
|
||||||
Assertions.assertEquals(false, userKey.getEnable());
|
Assertions.assertEquals(false, userKey.getEnable());
|
||||||
//校验日志
|
//校验日志
|
||||||
checkLog(userKeyId, OperationLogType.UPDATE);
|
checkLog(userKeyId, OperationLogType.UPDATE);
|
||||||
|
//校验不存在的
|
||||||
|
requestGet(String.format(DISABLE, UUID.randomUUID().toString()), status().is5xxServerError());
|
||||||
|
|
||||||
|
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/login")
|
||||||
|
.content(String.format("{\"username\":\"%s\",\"password\":\"%s\"}", "test-user-key", "test-user-key@metersphere.io"))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andReturn();
|
||||||
|
String sessionId = JsonPath.read(mvcResult.getResponse().getContentAsString(), "$.data.sessionId");
|
||||||
|
String csrfToken = JsonPath.read(mvcResult.getResponse().getContentAsString(), "$.data.csrfToken");
|
||||||
|
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders.get(String.format(DISABLE, userKeyId))
|
||||||
|
.header(SessionConstants.HEADER_TOKEN, sessionId)
|
||||||
|
.header(SessionConstants.CSRF_TOKEN, csrfToken)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().is5xxServerError())
|
||||||
|
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
requestGetPermissionTest(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE, DISABLE);
|
requestGetPermissionTest(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE, DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +195,8 @@ public class UserApiKeysControllerTests extends BaseTest {
|
||||||
Assertions.assertEquals(true, userKey.getEnable());
|
Assertions.assertEquals(true, userKey.getEnable());
|
||||||
//校验日志
|
//校验日志
|
||||||
checkLog(userKeyId, OperationLogType.UPDATE);
|
checkLog(userKeyId, OperationLogType.UPDATE);
|
||||||
|
//校验不存在的
|
||||||
|
requestGet(String.format(ENABLE, UUID.randomUUID().toString()), status().is5xxServerError());
|
||||||
requestGetPermissionTest(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE, ENABLE);
|
requestGetPermissionTest(PermissionConstants.SYSTEM_PERSONAL_API_KEY_UPDATE, ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,4 +42,14 @@ values ('resourcePoolId1', 'resourcePoolName1', 'node', 'resourcePoolDescription
|
||||||
unix_timestamp() * 1000, 'admin', 1, 1, 1, 'http://localhost:8080', 1, 0);
|
unix_timestamp() * 1000, 'admin', 1, 1, 1, 'http://localhost:8080', 1, 0);
|
||||||
replace into project_test_resource_pool(project_id, test_resource_pool_id) value ('projectId', 'resourcePoolId');
|
replace into project_test_resource_pool(project_id, test_resource_pool_id) value ('projectId', 'resourcePoolId');
|
||||||
replace into project_test_resource_pool(project_id, test_resource_pool_id) value ('projectId', 'resourcePoolId1');
|
replace into project_test_resource_pool(project_id, test_resource_pool_id) value ('projectId', 'resourcePoolId1');
|
||||||
replace into test_resource_pool_organization(id , test_resource_pool_id, org_id) value (UUID_SHORT(),'resourcePoolId', '100001');
|
replace into test_resource_pool_organization(id , test_resource_pool_id, org_id) value (UUID_SHORT(),'resourcePoolId', '100001');
|
||||||
|
|
||||||
|
|
||||||
|
replace into user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source,
|
||||||
|
last_project_id, create_user, update_user)
|
||||||
|
VALUES ('test-user-key', 'test-user-key', 'test-user-key@metersphere.io', MD5('test-user-key@metersphere.io'),
|
||||||
|
UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, '100001', '', 'LOCAL', '100001100001', 'admin', 'admin');
|
||||||
|
|
||||||
|
replace INTO user_role_relation(id, user_id, role_id, source_id, organization_id, create_time, create_user)
|
||||||
|
VALUES ('test-user-key', 'test-user-key', 'admin', 'system',
|
||||||
|
'system', '1684747668375', 'admin');
|
|
@ -51,7 +51,7 @@
|
||||||
v-if="item.showDescInput"
|
v-if="item.showDescInput"
|
||||||
v-model:model-value="item.description"
|
v-model:model-value="item.description"
|
||||||
:placeholder="t('common.pleaseInput')"
|
:placeholder="t('common.pleaseInput')"
|
||||||
:max-length="255"
|
:max-length="1000"
|
||||||
@blur="handleDescChange(item)"
|
@blur="handleDescChange(item)"
|
||||||
></a-textarea>
|
></a-textarea>
|
||||||
<div v-else class="desc-line api-item-value">
|
<div v-else class="desc-line api-item-value">
|
||||||
|
@ -144,11 +144,11 @@
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item field="desc" :label="t('ms.personal.accessKeyDesc')">
|
<a-form-item field="desc" :label="t('ms.personal.accessKeyDesc')">
|
||||||
<a-input
|
<a-textarea
|
||||||
v-model:model-value="timeForm.desc"
|
v-model:model-value="timeForm.desc"
|
||||||
:max-length="255"
|
|
||||||
:placeholder="t('ms.personal.accessKeyDescPlaceholder')"
|
:placeholder="t('ms.personal.accessKeyDescPlaceholder')"
|
||||||
/>
|
:max-length="1000"
|
||||||
|
></a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
Loading…
Reference in New Issue