You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MockMvc时为何出现403 Forbidden错误?已用@WithMockUser

解决Spring Security下Mock测试Delete接口返回403的问题

问题分析

从错误日志能看到Handler: Type = null,说明请求没有匹配到对应的Controller方法,这是403的核心原因,另外还有请求体缺失、CSRF保护、Mock对象不匹配等问题需要一并修复。

修复步骤

1. 修正请求路径匹配

你的Controller方法标注@DeleteMapping("/deleteitem"),如果Controller类没有添加@RequestMapping("/admin")注解,测试请求路径应该是/deleteitem,而非/admin/deleteitem/;如果Controller类有@RequestMapping("/admin"),则路径应为/admin/deleteitem(去掉末尾多余的斜杠)。

2. 确保@WithMockUser注解正确配置

确认测试方法或类上添加了@WithMockUser,且角色与接口权限要求一致:

@Test
@WithMockUser(username = "tushar", roles = "ADMIN")
void testDeleteItem() throws Exception {
    // 测试逻辑
}

3. 携带请求体(满足@RequestBody要求)

Controller方法需要接收DeleteItemDto作为请求体,测试时要通过content()传递JSON格式的请求体:

// 先注入ObjectMapper
@Autowired
private ObjectMapper objectMapper;

// 在请求中添加请求体
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.delete("/admin/deleteitem")
        .accept(MediaType.APPLICATION_JSON)
        .contentType(MediaType.APPLICATION_JSON)
        .content(objectMapper.writeValueAsString(new DeleteItemDto(401)))) // 传入对应itemId的Dto实例
        .andReturn();

4. 处理CSRF保护

Spring Security默认开启CSRF,DELETE请求需要携带CSRF Token,测试中可以通过两种方式处理:

  • 方式一:在请求中添加CSRF Token
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.delete("/admin/deleteitem")
        .with(csrf()) // 手动添加CSRF Token
        .accept(MediaType.APPLICATION_JSON)
        .contentType(MediaType.APPLICATION_JSON)
        .content(objectMapper.writeValueAsString(new DeleteItemDto(401))))
        .andReturn();
  • 方式二:测试时关闭CSRF过滤(仅用于测试场景)
    在测试类上添加注解:
@AutoConfigureMockMvc(addFilters = false)

5. 修正Mock对象匹配问题

Service中是删除findById返回的对象,测试时要保证Mock的对象一致:

// 创建并设置Mock的Item对象
ItemsModel mockItem = new ItemsModel();
mockItem.setItemId(401);
// Mock findById返回该对象
Mockito.when(itemRepo.findById(401)).thenReturn(Optional.of(mockItem));
// Mock delete该对象的操作
doNothing().when(itemRepo).delete(mockItem);

完整修正后的测试代码示例

@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private ItemRepo itemRepo;

@Test
@WithMockUser(username = "tushar", roles = "ADMIN")
void testDeleteItem() throws Exception {
    // 准备测试数据
    ItemsModel mockItem = new ItemsModel();
    mockItem.setItemId(401);
    DeleteItemDto deleteDto = new DeleteItemDto(401);

    // Mock Repository方法
    Mockito.when(itemRepo.findById(401)).thenReturn(Optional.of(mockItem));
    doNothing().when(itemRepo).delete(mockItem);

    // 发送请求并验证结果
    MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.delete("/admin/deleteitem")
            .with(csrf())
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(deleteDto)))
            .andReturn();

    assertEquals(200, mvcResult.getResponse().getStatus());
}

内容的提问来源于stack exchange,提问作者Tushar Kawade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 18:50:27