Spring Boot测试中过期JWT未被拦截的问题咨询
问题:过期JWT令牌请求接口未返回401状态?
在Spring Boot测试中,使用已过期的JWT令牌请求/api/money-transfer接口,预期返回401未授权状态,但实际返回200成功状态。疑惑测试环境下Spring是否不校验JWT过期时间?是需要手动编码校验,还是能让Spring自动完成?
依赖配置
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <!-- ... --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
测试类代码
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MockMvc; import java.time.Instant; import java.time.temporal.ChronoUnit; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class TransferControllerTest { @Autowired MockMvc mockMvc; @Test void testUnauthorized() throws Exception { mockMvc .perform(patch("/api/money-transfer") .with(jwt().jwt(jwt -> jwt .claim("userid", 15L) .expiresAt(Instant.now().minus(1, ChronoUnit.DAYS)))) .andExpect(status().isUnauthorized()); } }
控制器代码
package com.example.pixel_money_transfer_api.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/money-transfer") public class TransferController { @PatchMapping public ResponseEntity<Void> performTransfer() { return ResponseEntity.ok().build(); // gutted every bit of logic } }
错误信息
java.lang.AssertionError: Status expected:<401> but was:<200> Expected :401 Actual :200
原因与解决办法
使用SecurityMockMvcRequestPostProcessors.jwt()生成的测试用JWT默认不会触发过期校验——这个处理器只是模拟JWT认证通过的状态,不会自动应用完整的OAuth2资源服务器校验规则。
要让测试环境中Spring自动校验JWT过期时间,可通过以下两种方式解决:
方法1:手动模拟过期认证失败
直接创建标记为未认证的JWT凭证,模拟过期校验失败的场景:
@Test void testUnauthorized() throws Exception { // 构建过期JWT Jwt expiredJwt = Jwt.withTokenValue("dummy-token") .claim("userid", 15L) .expiresAt(Instant.now().minus(1, ChronoUnit.DAYS)) .build(); // 创建未认证的JWT令牌对象 JwtAuthenticationToken authToken = new JwtAuthenticationToken(expiredJwt); authToken.setAuthenticated(false); mockMvc .perform(patch("/api/money-transfer") .with(SecurityMockMvcRequestPostProcessors.authentication(authToken))) .andExpect(status().isUnauthorized()); }
方法2:配置完整的OAuth2资源服务器规则
确保Spring Security配置类中正确启用JWT校验,让测试环境自动应用校验逻辑:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(jwtAuthenticationConverter()))); return http.build(); } private JwtAuthenticationConverter jwtAuthenticationConverter() { JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); // 可添加自定义权限提取逻辑 return converter; } }
配置完成后,原测试代码中设置过期时间的JWT会被Spring Security自动校验并返回401。
注意:如果测试类未加载到Security配置类,可通过@Import(SecurityConfig.class)手动导入。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

