Spring Boot 3中Mock JWT认证令牌测试失效问题求助
排查Spring Boot 3中JWT测试认证上下文失效问题
以下是针对你的场景的具体排查步骤:
1. 确认自定义注解的核心配置
- 检查
@WithMockJwtUser注解是否添加了@WithSecurityContext注解绑定工厂类:@Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithMockJwtUserSecurityContextFactory.class) public @interface WithMockJwtUser { // 你的注解属性,比如username、roles等 } - 验证工厂类的
createSecurityContext方法是否生成了有效且已认证的JwtAuthenticationToken:@Override public SecurityContext createSecurityContext(WithMockJwtUser annotation) { SecurityContext context = SecurityContextHolder.createEmptyContext(); // 构建符合业务要求的JWT对象 Jwt mockJwt = Jwt.withTokenValue("mock-jwt-token") .claim("sub", annotation.username()) .claim("roles", annotation.roles()) .build(); // 生成已认证的JWT认证令牌 JwtAuthenticationToken authToken = new JwtAuthenticationToken( mockJwt, AuthorityUtils.createAuthorityList(annotation.roles()), annotation.username() ); authToken.setAuthenticated(true); context.setAuthentication(authToken); return context; }
2. 检查测试类的注解配置
- 如果使用
@WebMvcTest,必须手动导入Security配置类,因为该注解默认不会加载完整的Security上下文:@WebMvcTest(TestController.class) @Import(SecurityConfig.class) // 导入你的自定义Security配置 @AutoConfigureMockMvc public class TestControllerTest { // 测试代码 } - 若使用
@SpringBootTest,确保没有排除SecurityAutoConfiguration,且测试环境加载的Security配置与生产一致。
3. 排查认证类型不匹配问题
@WithMockUser默认生成UsernamePasswordAuthenticationToken,而你的Security配置只接受JwtAuthenticationToken类型的认证,因此@WithMockUser必然失效,必须使用自定义的@WithMockJwtUser生成JWT类型的认证对象。
4. 验证SecurityContext的生命周期
- 检查测试类的
@BeforeEach/@AfterEach方法,确认没有手动调用SecurityContextHolder.clearContext()提前清空上下文。 - 开启Spring Security DEBUG日志,跟踪上下文变化:
在application-test.properties中添加:
查找日志中类似logging.level.org.springframework.security=DEBUGSet SecurityContextHolder to anonymous SecurityContext的输出,定位是哪个过滤器或组件替换了上下文。
5. 检查过滤器链顺序
- 确保自定义Security配置中,
JwtAuthenticationFilter的执行顺序早于AnonymousAuthenticationFilter。可以通过@Order注解调整顺序,或者在配置类中明确指定:
上述配置中,Spring Boot 3默认会将JWT过滤器置于匿名过滤器之前,若你自定义了过滤器链,需确保顺序正确。@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()); return http.build(); }
内容的提问来源于stack exchange,提问作者ScorprocS
相关产品推荐
相关产品推荐

