如何根据测试注解为MockMvc请求自动添加Authorization请求头?
我来给你拆解一下实现这个需求的方案,核心是借助Spring Test的测试上下文和MockMvc的请求后置处理器,让带有@WithJwt注解的测试方法自动注入Authorization请求头,不用每次手动编写.header()代码。
步骤1:自定义JWT授权请求后置处理器
首先我们需要一个RequestPostProcessor,它能识别当前测试方法是否带有@WithJwt注解,并自动添加对应的请求头。这里我们通过TestContextManager获取当前执行的测试方法信息:
import org.springframework.test.context.TestContextManager; import org.springframework.test.web.servlet.RequestPostProcessor; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; public class JwtAuthRequestPostProcessor implements RequestPostProcessor { private final TestContextManager testContextManager; public JwtAuthRequestPostProcessor(TestContextManager testContextManager) { this.testContextManager = testContextManager; } @Override public HttpServletRequest postProcessRequest(HttpServletRequest request) { try { // 获取当前正在执行的测试方法 Method testMethod = testContextManager.getTestContext().getTestMethod(); WithJwt withJwt = testMethod.getAnnotation(WithJwt.class); if (withJwt != null) { // 这里可以根据@WithJwt的属性动态生成JWT,示例用固定值"Bearer foo" String jwtToken = "Bearer foo"; request.addHeader("Authorization", jwtToken); } } catch (Exception e) { throw new RuntimeException("Failed to add JWT authorization header", e); } return request; } }
步骤2:在测试类中配置MockMvc
接下来不要直接依赖@Autowired注入的MockMvc,而是手动构建MockMvc并添加我们自定义的后置处理器。同时注入TestContextManager来传递测试上下文信息:
@RunWith(SpringRunner.class) @EnableSpringDataWebSupport @WebMvcTest(MyController.class) @Import({WebSecurityConfig.class}) public class MyControllerTest { @Autowired private WebApplicationContext webApplicationContext; @Autowired private TestContextManager testContextManager; protected MockMvc mockMvc; @BeforeEach public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) // 添加全局请求后置处理器 .defaultRequest(new JwtAuthRequestPostProcessor(testContextManager)) .build(); } @Test @WithJwt(principal = "admin", authorities = {"READ_USERS"}) public void readUsersAuthorityCanListUsers() throws Exception { final List<User> users = Arrays.asList(admin, user); when(userRepo.findAll(any(Pageable.class))).thenReturn(new PageImpl<>(users)); // 这里不需要手动添加Authorization头了! this.mockMvc .perform(get("/")) .andExpect(status().isOk()) .andExpect(jsonPath("$.content", hasSize(users.size()))); } @Test // 没有@WithJwt注解,不会自动添加Authorization头 public void unauthenticatedRequestShouldFail() throws Exception { this.mockMvc .perform(get("/")) .andExpect(status().isUnauthorized()); } }
步骤3:封装成可复用的MockMvc配置器(可选)
如果多个测试类都需要这个功能,我们可以把逻辑封装成MockMvcConfigurer,方便复用:
import org.springframework.test.context.TestContextManager; import org.springframework.test.web.servlet.MockMvcConfigurer; import org.springframework.test.web.servlet.config.ConfigurableMockMvcBuilder; public class JwtAuthMockMvcConfigurer implements MockMvcConfigurer { private final TestContextManager testContextManager; public JwtAuthMockMvcConfigurer(TestContextManager testContextManager) { this.testContextManager = testContextManager; } @Override public void afterConfigurerAdded(ConfigurableMockMvcBuilder<?> builder) { builder.defaultRequest(new JwtAuthRequestPostProcessor(testContextManager)); } }
然后在测试类的setup方法中使用:
@BeforeEach public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .apply(new JwtAuthMockMvcConfigurer(testContextManager)) .build(); }
进阶:动态生成JWT Token
如果你的@WithJwt注解的principal和authorities是用来生成真实JWT的,可以在处理器中根据注解属性动态生成token,比如:
if (withJwt != null) { // 假设你有一个JwtTokenUtil工具类来生成token String jwtToken = "Bearer " + jwtTokenUtil.generateToken(withJwt.principal(), withJwt.authorities()); request.addHeader("Authorization", jwtToken); }
注意事项
- 确保
TestContextManager能被正确注入,Spring Test会自动管理这个bean,直接用@Autowired即可。 - 如果之前依赖自动配置的MockMvc,需要改为手动构建才能添加自定义处理器。
- 全局后置处理器会作用于所有请求,但只有带有
@WithJwt注解的测试方法才会添加Authorization头,不会影响其他测试。
内容的提问来源于stack exchange,提问作者ch4mp
相关产品推荐
相关产品推荐

