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

Spring Boot集成测试用Bearer Token报错:SecurityContext无Authentication对象

Spring Boot集成测试中@PreAuthorize权限验证问题修复

问题描述

在编写Spring Boot集成测试时,UserController的方法使用了@PreAuthorize注解指定角色权限,但运行测试时抛出以下错误:

jakarta.servlet.ServletException: Request processing failed: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

相关代码片段如下:

AbstractRestControllerTest

@SpringBootTest
@ExtendWith(MockitoExtension.class)
@ActiveProfiles(value = "test")
@AutoConfigureMockMvc(addFilters = false)
public abstract class AbstractRestControllerTest {

    @Autowired
    protected MockMvc mockMvc;

}

UserController

@RestController
@RequestMapping("/api/v1/user")
@RequiredArgsConstructor
@Validated
class UserController {

    private final UserService userService;

    private final UserToUserResponseMapper userToUserResponseMapper = UserToUserResponseMapper.initialize();
    private final UserToUsersResponseMapper userToUsersResponseMapper = UserToUsersResponseMapper.initialize();

    @PostMapping
    @PreAuthorize("hasAnyAuthority('ADMIN')")
    public Response<Void> saveUser(@RequestBody @Valid UserSaveRequest saveRequest) {
        userService.saveUser(saveRequest);
        return Response.SUCCESS;
    }
}

UserControllerTest

class UserControllerTest extends AbstractRestControllerTest {

     @MockBean
    private UserService userService;

    private static final String BASE_PATH = "/api/v1/user";

    @Test
    void saveUserRequestWithAdminRole_ReturnSuccess() throws Exception {
        // Given
        UserSaveRequest mockUserSaveRequest = new UserSaveRequestBuilder()
                .withFirstName("First Name")
                .build();
        Token mockToken = TokenBuilder.VALID_FOR_ADMIN;
        Response<Void> mockResponse = ResponseBuilder.SUCCESS;

        // When
        Mockito.doNothing().when(userService).saveUser(mockUserSaveRequest);

        // Then
        mockMvc.perform(MockMvcRequestBuilders
                        .post(BASE_PATH, mockToken.getAccessToken(), mockUserSaveRequest))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.time").isNotEmpty())
                .andExpect(jsonPath("$.httpStatus").value(mockResponse.getHttpStatus().getReasonPhrase()))
                .andExpect(jsonPath("$.isSuccess").value(mockResponse.getIsSuccess()))
                .andExpect(jsonPath("$.response").doesNotExist());

        Mockito.verify(userService, Mockito.times(1)).saveUser(Mockito.any());

    }
}

原因分析

  1. @AutoConfigureMockMvc(addFilters = false)禁用了所有Servlet过滤器,包括Spring Security的认证过滤器。这导致请求头中的Bearer token无法被解析处理,SecurityContext中没有生成对应的Authentication对象。
  2. @PreAuthorize注解需要从SecurityContext中获取当前用户的权限信息,由于缺少Authentication对象,直接抛出认证凭证未找到的异常。

修复方案

方案一:使用@WithMockUser快速模拟认证用户(仅测试权限逻辑)

这种方式跳过真实的token认证流程,直接模拟拥有指定权限的用户:

  1. 在测试方法上添加@WithMockUser注解,指定用户权限:
@Test
@WithMockUser(authorities = "ADMIN") // 模拟拥有ADMIN权限的用户
void saveUserRequestWithAdminRole_ReturnSuccess() throws Exception {
    // 原测试逻辑保持不变
}
  1. 保留AbstractRestControllerTest中的@AutoConfigureMockMvc(addFilters = false),因为我们不需要通过过滤器处理token。

方案二:启用Security过滤器,模拟真实认证流程(测试完整认证+权限逻辑)

如果你需要测试真实的token解析和认证流程,可以按以下步骤修改:

  1. 修改AbstractRestControllerTest的注解,移除addFilters = false,让Spring Security过滤器生效:
@SpringBootTest
@ExtendWith(MockitoExtension.class)
@ActiveProfiles(value = "test")
@AutoConfigureMockMvc // 移除addFilters = false
public abstract class AbstractRestControllerTest {

    @Autowired
    protected MockMvc mockMvc;

}
  1. 使用Spring Security测试工具类模拟JWT认证,在请求中添加权限信息:
mockMvc.perform(MockMvcRequestBuilders
                .post(BASE_PATH, mockToken.getAccessToken(), mockUserSaveRequest)
                // 模拟JWT认证并添加ADMIN权限
                .with(SecurityMockMvcRequestPostProcessors.jwt()
                        .authorities(new SimpleGrantedAuthority("ADMIN"))))
                .andDo(print())
                .andExpect(status().isOk())
                // 后续断言保持不变
  1. (可选)如果你的项目使用自定义JWT认证,需要在test环境配置文件中添加对应的JWT密钥等参数,确保测试token能被正确解析。

内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:35:24