feat: Implement pagination and effective account validation for backdoor user login

This commit is contained in:
2026-07-20 20:49:23 +08:00
parent de42645cae
commit 0c1c41772e
14 changed files with 268 additions and 93 deletions

View File

@@ -41,7 +41,7 @@ class BackDoorLoginControllerTest
{
when(loginService.listAvailableUsers("tester", 100)).thenReturn(Collections.emptyList());
ResponseEntity<String> response = controller.backDoor(null, "tester");
ResponseEntity<String> response = controller.backDoor(null, "tester", "1");
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().contains("选择一个 PC 用户登录"));
@@ -54,7 +54,7 @@ class BackDoorLoginControllerTest
@Test
void malformedIdReturnsHtmlErrorWithoutAttemptingLogin()
{
ResponseEntity<String> response = controller.backDoor("not-a-number", null);
ResponseEntity<String> response = controller.backDoor("not-a-number", null, null);
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
assertTrue(response.getBody().contains("用户 ID 必须是正整数"));
@@ -69,11 +69,13 @@ class BackDoorLoginControllerTest
user.setUserName("tester");
when(loginService.login(8L)).thenReturn(new LoginSession(user, "signed-token"));
ResponseEntity<String> response = controller.backDoor("8", null);
ResponseEntity<String> response = controller.backDoor("8", null, null);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().contains("const token = \"signed-token\""));
assertTrue(response.getBody().contains("localStorage.setItem('access_token', token)"));
assertTrue(response.getBody().contains("window.location.replace(portalUrl)"));
assertFalse(response.getBody().contains("/management/"));
assertFalse(response.getBody().contains("?token=signed-token"));
}
}

View File

@@ -1,6 +1,8 @@
package com.ruoyi.web.controller.system;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
@@ -28,7 +30,7 @@ class BackDoorPageRendererTest
dept.setDeptName("研发 <一部>");
user.setDept(dept);
String html = renderer.renderUserList(Collections.singletonList(user), "<script>", 100);
String html = renderer.renderUserList(Collections.singletonList(user), "<script>", 100, 1, 8);
assertFalse(html.contains("<script>alert(1)</script>"));
assertTrue(html.contains("tester&lt;/td&gt;&lt;script&gt;alert(1)&lt;/script&gt;"));
@@ -36,6 +38,31 @@ class BackDoorPageRendererTest
assertTrue(html.contains("138****5678"));
assertTrue(html.contains("研发 &lt;一部&gt;"));
assertTrue(html.contains("?id=7"));
assertTrue(html.contains("html, body { width: 100%; height: 100%; overflow: hidden; }"));
}
@Test
void userListPaginatesWithoutRenderingOffPageUsers()
{
List<SysUser> users = new ArrayList<>();
for (long userId = 1; userId <= 9; userId++)
{
SysUser user = new SysUser();
user.setUserId(userId);
user.setUserName("tester" + userId);
users.add(user);
}
String firstPage = renderer.renderUserList(users, "", 100, 1, 8);
String secondPage = renderer.renderUserList(users, "", 100, 2, 8);
assertTrue(firstPage.contains("?id=8"));
assertFalse(firstPage.contains("?id=9"));
assertTrue(firstPage.contains("第 1 / 2 页"));
assertTrue(firstPage.contains("?page=2"));
assertTrue(secondPage.contains("?id=9"));
assertFalse(secondPage.contains("?id=8"));
assertTrue(secondPage.contains("第 2 / 2 页"));
}
@Test
@@ -52,7 +79,10 @@ class BackDoorPageRendererTest
assertFalse(html.contains("token</script>"));
assertTrue(html.contains("token\\u003c/script\\u003e"));
assertTrue(html.contains("localStorage.setItem('access_token', token)"));
assertTrue(html.contains("fetch(apiBase + '/getInfo'"));
assertTrue(html.contains("window.location.replace(portalUrl)"));
assertFalse(html.contains("/management/"));
assertFalse(html.contains("userType"));
assertFalse(html.contains("/getInfo"));
assertFalse(html.contains("?token="));
}
}

View File

@@ -62,6 +62,7 @@ class BackDoorLoginServiceTest
SysUser user = activeUser(12L);
LoginUser loginUser = org.mockito.Mockito.mock(LoginUser.class);
when(userMapper.selectUserById(12L)).thenReturn(user);
when(userMapper.selectBackDoorEffectiveUserId("tester")).thenReturn(12L);
when(userDetailsService.createLoginUser(user)).thenReturn(loginUser);
when(tokenService.createTokenHourTwo(loginUser)).thenReturn("test-token");
@@ -99,6 +100,19 @@ class BackDoorLoginServiceTest
verify(tokenService, never()).createTokenHourTwo(org.mockito.ArgumentMatchers.any());
}
@Test
void loginRejectsObsoleteDuplicateAccount()
{
SysUser obsoleteUser = activeUser(11L);
when(userMapper.selectUserById(11L)).thenReturn(obsoleteUser);
when(userMapper.selectBackDoorEffectiveUserId("tester")).thenReturn(12L);
ServiceException exception = assertThrows(ServiceException.class, () -> service.login(11L));
assertEquals("该账号存在更新记录,请从用户列表选择有效账号", exception.getMessage());
verify(tokenService, never()).createTokenHourTwo(org.mockito.ArgumentMatchers.any());
}
private SysUser activeUser(Long userId)
{
SysUser user = new SysUser();