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

Spring Boot集成测试:如何预填充安全上下文的Principal

问题描述

我有一个暴露REST API的微服务,通过application.yml中的默认Spring Boot配置采用OAuth2进行安全保护:

security:
  oauth2:
    client:
      client-id: ...
      client-secret: ...
      grant-type: ...
    resource:
      user-info-uri: ...
      token-info-uri: ...
      prefer-token-info: false

API方法使用常规注解,用户在前端完成授权后,通过请求头携带Authorization: Bearer ...令牌向API发送授权请求。后端可在控制器方法中注入Principal参数读取用户详情,示例如下:

@CrossOrigin
@RestController
@RequestMapping("/foo")
@ContextConfiguration
public class MyController {

    @GetMapping("/all")
    public ResponseEntity<List<String>> sampleMethod(Principal user) { // <<<- 集成测试时Principal不应为null
        // 业务代码
    }
}

微服务实际运行时功能正常,但使用MockMvc执行@SpringBootTest集成测试时,Principal始终为null:

@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
@DirtiesContext
class MyControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void shouldReturnOk() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/all"))
                .andExpect(status().isOk());
    }

}

请问如何简便配置@SpringBootTest集成测试,使安全上下文预填充一个可由我控制的Principal?

解决方案

方法1:请求内直接绑定认证用户

这是最简便的方式,在测试请求中通过with(user(...))快速设置自定义Principal:

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;

@Test
void shouldReturnOk() throws Exception {
    // 自定义Principal实现
    Principal mockPrincipal = () -> "test-user-123";
    
    mockMvc.perform(MockMvcRequestBuilders.get("/foo/all")
                    .with(user(mockPrincipal.getName())))
            .andExpect(status().isOk());
}

如果需要配置用户权限、角色,可构建完整的认证对象:

@Test
void shouldReturnOkWithAuthorities() throws Exception {
    Authentication auth = User.withUsername("test-user")
            .password("无需实际密码")
            .authorities("ROLE_USER", "ROLE_ADMIN")
            .build();
    
    mockMvc.perform(MockMvcRequestBuilders.get("/foo/all")
                    .with(user(auth)))
            .andExpect(status().isOk());
}

方法2:全局配置测试认证用户

如果所有测试用例都需要相同的认证上下文,可在测试类上添加@WithMockUser注解,自动填充安全上下文:

@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
@DirtiesContext
@WithMockUser(username = "test-user", authorities = {"ROLE_USER"}) // 全局生效
class MyControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void shouldReturnOk() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/foo/all"))
                .andExpect(status().isOk());
    }
}

该注解会自动生成带有指定用户名、权限的认证对象,控制器中的Principal参数将被正确注入。

方法3:模拟真实OAuth2令牌请求

如果需要贴近生产场景的测试(携带Authorization头),可构造模拟令牌并添加到请求头:

@Test
void shouldReturnOkWithOAuth2Token() throws Exception {
    // 模拟JWT令牌(实际测试可使用测试JWT生成工具生成符合格式的令牌)
    String mockToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QtdXNlciJ9.SW9D1XaZ7eS5PzQ0JfL8aA";
    
    mockMvc.perform(MockMvcRequestBuilders.get("/foo/all")
                    .header("Authorization", "Bearer " + mockToken))
            .andExpect(status().isOk());
}

若需要服务端正确解析令牌,可通过@MockBean替换OAuth2资源服务器的令牌解析器,或在测试配置中设置模拟的令牌验证逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:42:24