package com.label.integration; import com.label.AbstractIntegrationTest; import com.label.module.user.dto.LoginRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.*; import java.util.Map; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; /** * 用户管理集成测试(US7)。 * * 测试场景: * 1. 变更角色后权限下一次请求立即生效(无需重新登录) * 2. 禁用账号后现有 Token 下一次请求立即返回 401 */ public class UserManagementIntegrationTest extends AbstractIntegrationTest { @Autowired private TestRestTemplate restTemplate; private String adminToken; @BeforeEach void setup() { adminToken = loginAndGetToken("DEMO", "admin", "admin123"); assertThat(adminToken).isNotBlank(); } // ------------------------------------------------------------------ 测试 1: 角色变更立即生效 -- @Test @DisplayName("创建用户为 ANNOTATOR,变更为 REVIEWER 后同一 Token 立即可访问审批接口") void updateRole_takesEffectImmediately() { String uniqueUsername = "testuser-" + UUID.randomUUID().toString().substring(0, 8); // 1. 创建 ANNOTATOR 用户 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + adminToken); headers.setContentType(MediaType.APPLICATION_JSON); ResponseEntity createResp = restTemplate.exchange( baseUrl("/api/users"), HttpMethod.POST, new HttpEntity<>(Map.of( "username", uniqueUsername, "password", "test1234", "realName", "测试用户", "role", "ANNOTATOR" ), headers), Map.class); assertThat(createResp.getStatusCode()).isEqualTo(HttpStatus.OK); @SuppressWarnings("unchecked") Map userData = (Map) createResp.getBody().get("data"); Long newUserId = ((Number) userData.get("id")).longValue(); // 2. 新用户登录获取 Token String userToken = loginAndGetToken("DEMO", uniqueUsername, "test1234"); assertThat(userToken).isNotBlank(); // 3. 验证:ANNOTATOR 无法访问待审批队列(REVIEWER 专属)→ 403 ResponseEntity beforeRoleChange = restTemplate.exchange( baseUrl("/api/tasks/pending-review"), HttpMethod.GET, bearerRequest(userToken), Map.class); assertThat(beforeRoleChange.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN); // 4. ADMIN 变更角色为 REVIEWER ResponseEntity roleResp = restTemplate.exchange( baseUrl("/api/users/" + newUserId + "/role"), HttpMethod.PUT, new HttpEntity<>(Map.of("role", "REVIEWER"), headers), Map.class); assertThat(roleResp.getStatusCode()).isEqualTo(HttpStatus.OK); // 5. 验证:同一 Token 下次请求立即具有 REVIEWER 权限 → 200 ResponseEntity afterRoleChange = restTemplate.exchange( baseUrl("/api/tasks/pending-review"), HttpMethod.GET, bearerRequest(userToken), Map.class); assertThat(afterRoleChange.getStatusCode()) .as("角色变更后同一 Token 应立即具有 REVIEWER 权限") .isEqualTo(HttpStatus.OK); } // ------------------------------------------------------------------ 测试 2: 禁用账号 Token 立即失效 -- @Test @DisplayName("禁用账号后,现有 Token 下一次请求立即返回 401") void disableAccount_tokenInvalidatedImmediately() { String uniqueUsername = "testuser-" + UUID.randomUUID().toString().substring(0, 8); // 1. 创建用户 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + adminToken); headers.setContentType(MediaType.APPLICATION_JSON); ResponseEntity createResp = restTemplate.exchange( baseUrl("/api/users"), HttpMethod.POST, new HttpEntity<>(Map.of( "username", uniqueUsername, "password", "test1234", "realName", "测试用户", "role", "ANNOTATOR" ), headers), Map.class); assertThat(createResp.getStatusCode()).isEqualTo(HttpStatus.OK); @SuppressWarnings("unchecked") Map userData = (Map) createResp.getBody().get("data"); Long newUserId = ((Number) userData.get("id")).longValue(); // 2. 新用户登录,获取 Token String userToken = loginAndGetToken("DEMO", uniqueUsername, "test1234"); assertThat(userToken).isNotBlank(); // 3. 验证 Token 有效 ResponseEntity meResp = restTemplate.exchange( baseUrl("/api/auth/me"), HttpMethod.GET, bearerRequest(userToken), Map.class); assertThat(meResp.getStatusCode()).isEqualTo(HttpStatus.OK); // 4. ADMIN 禁用账号 ResponseEntity disableResp = restTemplate.exchange( baseUrl("/api/users/" + newUserId + "/status"), HttpMethod.PUT, new HttpEntity<>(Map.of("status", "DISABLED"), headers), Map.class); assertThat(disableResp.getStatusCode()).isEqualTo(HttpStatus.OK); // 5. 验证:禁用后,现有 Token 立即失效 → 401 ResponseEntity meAfterDisable = restTemplate.exchange( baseUrl("/api/auth/me"), HttpMethod.GET, bearerRequest(userToken), Map.class); assertThat(meAfterDisable.getStatusCode()) .as("禁用账号后现有 Token 应立即失效") .isEqualTo(HttpStatus.UNAUTHORIZED); } // ------------------------------------------------------------------ 工具方法 -- private String loginAndGetToken(String companyCode, String username, String password) { LoginRequest req = new LoginRequest(); req.setCompanyCode(companyCode); req.setUsername(username); req.setPassword(password); ResponseEntity response = restTemplate.postForEntity( baseUrl("/api/auth/login"), req, Map.class); if (!response.getStatusCode().is2xxSuccessful()) { return null; } @SuppressWarnings("unchecked") Map data = (Map) response.getBody().get("data"); return (String) data.get("token"); } private HttpEntity bearerRequest(String token) { HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + token); return new HttpEntity<>(headers); } }