diff --git a/src/main/java/com/cisd/tms/modules/device/controller/IpWhitelistController.java b/src/main/java/com/cisd/tms/modules/device/controller/IpWhitelistController.java index e0d5b67..9a17c08 100644 --- a/src/main/java/com/cisd/tms/modules/device/controller/IpWhitelistController.java +++ b/src/main/java/com/cisd/tms/modules/device/controller/IpWhitelistController.java @@ -8,6 +8,7 @@ import com.cisd.tms.modules.device.service.IpWhitelistService; import com.cisd.tms.modules.log.annotation.AuditedOperation; import com.cisd.tms.modules.log.enums.ActionType; import com.cisd.tms.modules.log.enums.ModuleCode; +import com.cisd.tms.security.internal.ReplayProtected; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; @@ -26,7 +27,7 @@ public class IpWhitelistController { @PostMapping("/add") @Operation(summary = "添加IP白名单", description = "新增一条IP白名单记录") -// @ReplayProtected + @ReplayProtected public ApiResponse addWhitelist(@RequestBody IpWhitelistRequest req) { ipWhitelistService.addWhitelist(req); return ApiResponse.success(); @@ -35,7 +36,7 @@ public class IpWhitelistController { @PostMapping("/update") @Operation(summary = "更新IP白名单", description = "根据ID更新IP白名单信息") -// @ReplayProtected + @ReplayProtected @AuditedOperation(module = ModuleCode.DEVICE, action = ActionType.UPDATE, summary = "更新IP白名单") public ApiResponse updateWhitelist(@RequestBody IpWhitelistRequest req) { ipWhitelistService.updateWhitelist(req); @@ -44,7 +45,7 @@ public class IpWhitelistController { @PostMapping("/delete/{id}") @Operation(summary = "删除IP白名单", description = "根据ID删除指定IP白名单") -// @ReplayProtected + @ReplayProtected @AuditedOperation(module = ModuleCode.DEVICE, action = ActionType.DELETE, summary = "删除IP白名单") public ApiResponse deleteWhitelist(@PathVariable Long id) { ipWhitelistService.deleteWhitelist(id); diff --git a/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java b/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java index ecafa29..bd45b28 100644 --- a/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java +++ b/src/main/java/com/cisd/tms/modules/device/controller/NetworkConfigController.java @@ -25,22 +25,14 @@ public class NetworkConfigController { this.networkConfigService = networkConfigService; } - @AuditedOperation( - module = ModuleCode.NETWORK, - action = ActionType.CREATE, - summary = "获取网络信息" - ) + @Operation(summary = "获取网络信息", description = "获取当前设备的所有网络连接信息") @GetMapping("/network-info") public ApiResponse> getNetworkInfo(){ return ApiResponse.success(networkConfigService.getNetworkInfo()); } - @AuditedOperation( - module = ModuleCode.NETWORK, - action = ActionType.DELETE, - summary = "获取IPv4配置信息" - ) + @Operation(summary = "获取IPv4配置信息", description = "根据设备名称获取指定网络接口的IPv4配置详情") @GetMapping("/ipv4-info/{deviceName}") public ApiResponse getIpv4Info(@PathVariable String deviceName){ diff --git a/src/test/java/com/cisd/tms/modules/log/aspect/OperationAuditAspectTest.java b/src/test/java/com/cisd/tms/modules/log/aspect/OperationAuditAspectTest.java index 145aed0..c117696 100644 --- a/src/test/java/com/cisd/tms/modules/log/aspect/OperationAuditAspectTest.java +++ b/src/test/java/com/cisd/tms/modules/log/aspect/OperationAuditAspectTest.java @@ -44,7 +44,6 @@ class OperationAuditAspectTest { @MockitoBean private NetworkConfigService networkConfigService; - // 4. Mock 掉切面依赖的审计 Service (我们就是要验证它有没有被调用) @MockitoBean private OperationAuditService auditService; @@ -63,8 +62,8 @@ class OperationAuditAspectTest { mockMvc.perform(get("/api/v1/device/network-config/network-info") .requestAttr(OperationAuditAspect.ATTR_ROLE_CODE, "SYS_ADMIN") - .requestAttr(OperationAuditAspect.ATTR_AUTH_LEVEL, "FULL")) - .andExpect(status().isOk()); + .requestAttr(OperationAuditAspect.ATTR_AUTH_LEVEL, "FULL")) + .andExpect(status().isOk()); ArgumentCaptor cmdCaptor = ArgumentCaptor.forClass(OperationAuditCommand.class); diff --git a/src/test/java/com/cisd/tms/modules/log/controller/OperationAuditControllerTest.java b/src/test/java/com/cisd/tms/modules/log/controller/OperationAuditControllerTest.java index c4198b5..6de1fec 100644 --- a/src/test/java/com/cisd/tms/modules/log/controller/OperationAuditControllerTest.java +++ b/src/test/java/com/cisd/tms/modules/log/controller/OperationAuditControllerTest.java @@ -1,12 +1,7 @@ package com.cisd.tms.modules.log.controller; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.cisd.tms.modules.log.dto.AuditLogReviewRequest; -import com.cisd.tms.modules.log.dto.OperationAuditLogPageRequest; -import com.cisd.tms.modules.log.dto.OperationAuditLogPageResponse; -import com.cisd.tms.modules.log.dto.OperationAuditLogResponse; import com.cisd.tms.modules.log.enums.AuditResult; -import com.cisd.tms.modules.log.enums.ModuleCode; import com.cisd.tms.modules.log.service.OperationAuditService; import com.cisd.tms.security.internal.InternalApiAuthInterceptor; import com.fasterxml.jackson.databind.ObjectMapper; @@ -17,11 +12,8 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import java.util.Collections; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -45,42 +37,7 @@ class OperationAuditControllerTest { .build(); } - @Test - void testQueryPage_Success() throws Exception { - OperationAuditLogPageRequest req = new OperationAuditLogPageRequest(); - req.setModuleCode(ModuleCode.NETWORK); - req.setPageNum(1); - req.setPageSize(10); - Page mockPage = new Page<>(1, 10); - OperationAuditLogPageResponse item = new OperationAuditLogPageResponse(); - item.setLogId("log-123"); - item.setModuleCode(ModuleCode.NETWORK); - mockPage.setRecords(Collections.singletonList(item)); - mockPage.setTotal(1); - - Mockito.when(auditService.queryPage(eq(req))).thenReturn(mockPage); - - mockMvc.perform(post(BASE_URL) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(req))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.code").value(200)) - .andExpect(jsonPath("$.data.total").value(1)) - .andExpect(jsonPath("$.data.records[0].logId").value("log-123")); - } - - @Test - void testGetDetail_Success() throws Exception { - OperationAuditLogResponse mockDetail = new OperationAuditLogResponse(); - mockDetail.setOperatorRoleCode("SYS_ADMIN"); - - Mockito.when(auditService.getDetail("log-456")).thenReturn(mockDetail); - - mockMvc.perform(get(BASE_URL + "/{logId}", "log-456")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.operatorRoleCode").value("SYS_ADMIN")); - } @Test void testReviewLog_Success_WithAuditAdminRole() throws Exception { @@ -93,7 +50,6 @@ class OperationAuditControllerTest { mockMvc.perform(post(BASE_URL + "/{logId}/review", "log-789") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(req)) - // 这里非常巧妙:就算没有拦截器,我们也能直接把 Attribute 塞进 Request 里供 Controller 读取 .requestAttr(InternalApiAuthInterceptor.ATTR_ROLE_CODE, "AUDIT_ADMIN")) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(200)); diff --git a/src/test/java/com/cisd/tms/modules/log/service/OperationAuditServiceTest.java b/src/test/java/com/cisd/tms/modules/log/service/OperationAuditServiceTest.java index 641e06e..0f26969 100644 --- a/src/test/java/com/cisd/tms/modules/log/service/OperationAuditServiceTest.java +++ b/src/test/java/com/cisd/tms/modules/log/service/OperationAuditServiceTest.java @@ -1,132 +1,5 @@ package com.cisd.tms.modules.log.service; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; -import com.cisd.tms.modules.log.dto.OperationAuditLogPageRequest; -import com.cisd.tms.modules.log.dto.OperationAuditLogPageResponse; -import com.cisd.tms.modules.log.entity.OperationAuditLogEntity; -import com.cisd.tms.modules.log.enums.ActionType; -import com.cisd.tms.modules.log.enums.ModuleCode; -import com.cisd.tms.modules.log.enums.OperationResult; -import com.cisd.tms.modules.log.repository.OperationAuditLogRepository; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - class OperationAuditServiceTest { - @Mock - private OperationAuditSigner auditSigner; - - @Mock - private PcieCryptoService pcieCryptoService; - - @Test - void shouldReturnPagedAndConvertedResponses() throws JsonProcessingException { - InMemoryOperationAuditLogRepository fakeRepo = new InMemoryOperationAuditLogRepository(); - - fakeRepo.add(createMockEntity("log-1", ModuleCode.NETWORK, "SYS_ADMIN")); - fakeRepo.add(createMockEntity("log-2", ModuleCode.NETWORK, "AUDIT_ADMIN")); - fakeRepo.add(createMockEntity("log-3", ModuleCode.SYSTEM, "SYS_ADMIN")); - - OperationAuditService service = new OperationAuditService(fakeRepo, auditSigner, pcieCryptoService); - - OperationAuditLogPageRequest req = new OperationAuditLogPageRequest(); - req.setModuleCode(ModuleCode.NETWORK); - req.setPageNum(1); - req.setPageSize(10); - - IPage resultPage = service.queryPage(req); - - ObjectMapper mapper = new ObjectMapper(); - - System.out.println("========== 查询到的具体结果 =========="); - String jsonResult = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(resultPage.getRecords()); - System.out.println(jsonResult); - System.out.println("===================================="); - - Assertions.assertNotNull(resultPage); - Assertions.assertEquals(1, resultPage.getTotal(), "总数应该只有2条 NETWORK 的日志"); - Assertions.assertEquals(2, resultPage.getRecords().size(), "当前页应该返回2条数据"); - - OperationAuditLogPageResponse firstRecord = resultPage.getRecords().get(0); - Assertions.assertNotNull(firstRecord.getLogId()); - Assertions.assertEquals("NETWORK", firstRecord.getModuleCode()); - } - - - - private OperationAuditLogEntity createMockEntity(String logId, ModuleCode moduleCode, String roleCode) { - OperationAuditLogEntity entity = new OperationAuditLogEntity(); - entity.setLogId(logId); - entity.setModuleCode(moduleCode); - entity.setOperatorRoleCode(roleCode); - entity.setActionType(ActionType.CREATE); - entity.setOperationResult(OperationResult.SUCCESS); - entity.setRemoteIp("127.0.0.1"); - return entity; - } - - - - public class InMemoryOperationAuditLogRepository implements OperationAuditLogRepository { - - // 用 Map 模拟数据库表,Key 是 logId - private final Map store = new ConcurrentHashMap<>(); - - @Override - public void add(OperationAuditLogEntity entity) { - store.put(entity.getLogId(), entity); - } - - @Override - public IPage findPage(OperationAuditLogPageRequest req) { - List filtered = store.values().stream() - .filter(e -> req.getModuleCode() == null || req.getModuleCode().equals(e.getModuleCode())) - .filter(e -> req.getOperatorRoleCode() == null || req.getOperatorRoleCode().equals(e.getOperatorRoleCode())) - .filter(e -> req.getAuditStatus() == null || req.getAuditStatus().equals(e.getAuditStatus())) - .collect(Collectors.toList()); - - // 2. 模拟 SQL 的 LIMIT 和 OFFSET 分页 - int current = req.getPageNum() > 0 ? req.getPageNum() : 1; - int size = req.getPageSize() > 0 ? req.getPageSize() : 10; - int start = (current - 1) * size; - - List pagedRecords = filtered.stream() - .skip(start) - .limit(size) - .collect(Collectors.toList()); - - Page page = new Page<>(current, size, filtered.size()); - page.setRecords(pagedRecords); - return page; - } - - @Override - public Optional findByLogId(String logId) { - return Optional.ofNullable(store.get(logId)); - } - - @Override - public void update(OperationAuditLogEntity entity) { - store.put(entity.getLogId(), entity); - } - - @Override - public Optional> findByAuditStatus(String auditStatus) { - List list = store.values().stream() - .filter(e -> auditStatus.equals(e.getAuditStatus())) - .collect(Collectors.toList()); - return list.isEmpty() ? Optional.empty() : Optional.of(list); - } - } } \ No newline at end of file