package com.label.integration; import com.label.AbstractIntegrationTest; import com.label.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; /** * 鐢ㄦ埛绠$悊闆嗘垚娴嬭瘯锛圲S7锛夈€? * * 娴嬭瘯鍦烘櫙锛? * 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. 楠岃瘉锛欰NNOTATOR 鏃犳硶璁块棶寰呭鎵归槦鍒楋紙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); } }