fix(系统设置): 用户管理页面,禁用和删除用户时如果相关用户正在登录中,则同步踢出

--bug=1034777 --user=宋天阳 [系统设置]操作-如果用户登录系统中,删除和禁用该用户,不会立即生效。 https://www.tapd.cn/55049933/s/1456050
This commit is contained in:
song-tianyang 2024-01-30 15:03:21 +08:00 committed by 刘瑞斌
parent bad97e06e4
commit 400c127061
2 changed files with 81 additions and 2 deletions

View File

@ -31,6 +31,7 @@ import io.metersphere.system.log.service.OperationLogService;
import io.metersphere.system.mapper.*;
import io.metersphere.system.notice.sender.impl.MailNoticeSender;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.SessionUtils;
import io.metersphere.system.utils.UserImportEventListener;
import jakarta.annotation.Resource;
import jakarta.mail.internet.InternetAddress;
@ -40,6 +41,7 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
@ -227,11 +229,18 @@ public class UserService {
userExample.createCriteria().andIdIn(
request.getSelectIds()
);
User updateUser = new User();
updateUser.setEnable(request.isEnable());
updateUser.setUpdateUser(operatorId);
updateUser.setUpdateTime(System.currentTimeMillis());
response.setSuccessCount(userMapper.updateByExampleSelective(updateUser, userExample));
if (BooleanUtils.isFalse(request.isEnable())) {
//如果是禁用批量踢出用户
request.getSelectIds().forEach(SessionUtils::kickOutUser);
}
return response;
}
@ -316,6 +325,8 @@ public class UserService {
response.setSuccessCount(this.deleteUserByList(userIdList, operatorId));
//删除用户角色关系
userRoleRelationService.deleteByUserIdList(userIdList);
//批量踢出用户
userIdList.forEach(SessionUtils::kickOutUser);
return response;
}

View File

@ -1,7 +1,9 @@
package io.metersphere.system.controller.user;
import com.jayway.jsonpath.JsonPath;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CodingUtils;
import io.metersphere.sdk.util.JSON;
@ -46,6 +48,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@ -55,11 +58,14 @@ import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -439,8 +445,29 @@ public class UserControllerTests extends BaseTest {
@Order(6)
public void testUserChangeEnableSuccess() throws Exception {
this.checkUserList();
//修改状态关闭
UserCreateInfo userInfo = USER_LIST.get(0);
//先使用要操作的用户登录,用于检查会不会把账户踢出
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/login")
.content(String.format("{\"username\":\"%s\",\"password\":\"%s\"}", userInfo.getEmail(), userInfo.getEmail()))
.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");
//检查该用户状态登录中
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/is-login");
requestBuilder
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN");
MvcResult loginResult = mockMvc.perform(requestBuilder).andReturn();
ResultHolder checkLoginHolder = JSON.parseObject(loginResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
Assertions.assertNotNull(checkLoginHolder.getData());
//修改状态关闭
UserChangeEnableRequest userChangeEnableRequest = new UserChangeEnableRequest();
userChangeEnableRequest.setSelectIds(new ArrayList<>() {{
this.add(userInfo.getId());
@ -452,10 +479,19 @@ public class UserControllerTests extends BaseTest {
new CheckLogModel(item, OperationLogType.UPDATE, UserRequestUtils.URL_USER_UPDATE_ENABLE)
);
}
UserDTO userDTO = this.getUserByEmail(userInfo.getEmail());
Assertions.assertEquals(userDTO.getEnable(), userChangeEnableRequest.isEnable());
//检查该用户被踢出
requestBuilder = MockMvcRequestBuilders.get("/is-login");
requestBuilder
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN");
loginResult = mockMvc.perform(requestBuilder).andReturn();
checkLoginHolder = JSON.parseObject(loginResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
Assertions.assertNull(checkLoginHolder.getData());
//修改状态开启
userChangeEnableRequest.setEnable(true);
this.requestPost(UserRequestUtils.URL_USER_UPDATE_ENABLE, userChangeEnableRequest, status().isOk());
@ -1064,6 +1100,27 @@ public class UserControllerTests extends BaseTest {
@Order(99)
public void testUserDeleteSuccess() throws Exception {
this.checkUserList();
//先使用要操作的用户登录,用于检查会不会把账户踢出
UserCreateInfo userInfo = USER_LIST.get(0);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/login")
.content(String.format("{\"username\":\"%s\",\"password\":\"%s\"}", userInfo.getEmail(), userInfo.getEmail()))
.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");
//检查该用户状态登录中
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/is-login");
requestBuilder
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN");
MvcResult loginResult = mockMvc.perform(requestBuilder).andReturn();
ResultHolder checkLoginHolder = JSON.parseObject(loginResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
Assertions.assertNotNull(checkLoginHolder.getData());
//删除USER_LIST用户
TableBatchProcessDTO request = new TableBatchProcessDTO();
request.setSelectIds(USER_LIST.stream().map(UserCreateInfo::getId).toList());
@ -1071,6 +1128,17 @@ public class UserControllerTests extends BaseTest {
userRequestUtils.responsePost(UserRequestUtils.URL_USER_DELETE, request), TableBatchProcessResponse.class);
Assertions.assertEquals(request.getSelectIds().size(), response.getTotalCount());
Assertions.assertEquals(request.getSelectIds().size(), response.getSuccessCount());
//检查该用户被踢出
requestBuilder = MockMvcRequestBuilders.get("/is-login");
requestBuilder
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN");
loginResult = mockMvc.perform(requestBuilder).andReturn();
checkLoginHolder = JSON.parseObject(loginResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
Assertions.assertNull(checkLoginHolder.getData());
//检查数据库
List<UserCreateInfo> removeList = new ArrayList<>();
for (UserCreateInfo deleteUser : USER_LIST) {