Spring Authorization Server的JUnit 5测试遇404问题求助
问题
为Spring Authorization Server编写JUnit 5测试用例时,请求/oauth2/token端点返回404错误,日志显示请求被映射到静态资源处理器,提示找不到对应资源;但使用Postman携带相同参数请求该端点却能成功完成授权。请问该端点未监听请求的原因是什么,该如何解决此问题?
测试代码
import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import java.util.Map; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @SpringBootTest class AuthorizationServerTests { @Autowired private WebApplicationContext context; private MockMvc mockMvc; @Test void testTokenEndpoint() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); // Test the token endpoint mockMvc.perform(post("/oauth2/token") .header("Authorization", "test") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .param("grant_type", "client_credentials") .param("scope", "read") .param("client_id", "test") .param("client_secret", "test")) .andExpect(status().isOk()) .andExpect(jsonPath("$.access_token").exists()); } }
错误日志
2024-12-30T00:11:41.836+02:00 INFO 8196 --- [test] [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 4 ms 2024-12-30T00:11:41.933+02:00 DEBUG 8196 --- [test] [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : POST "/oauth2/token", parameters={masked} 2024-12-30T00:11:41.956+02:00 DEBUG 8196 --- [test] [ Test worker] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]] 2024-12-30T00:11:41.978+02:00 DEBUG 8196 --- [test] [ Test worker] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found 2024-12-30T00:11:41.987+02:00 DEBUG 8196 --- [test] [ Test worker] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.servlet.resource.NoResourceFoundException: No static resource oauth2/token.] 2024-12-30T00:11:41.988+02:00 DEBUG 8196 --- [test] [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : Completed 404 NOT_FOUND
原因分析
- MockMvc未加载Spring Security过滤器链:Spring Authorization Server的端点由Spring Security负责注册和管理,直接通过
MockMvcBuilders.webAppContextSetup(context).build()初始化的MockMvc不会包含Spring Security的配置,导致端点未被正确映射,请求被默认路由到静态资源处理器。 - 无用的@Mock注解干扰上下文:测试类中使用了
@Mock注解但未配合@MockBean使用,可能导致Spring上下文初始化不完整,影响Authorization Server配置的加载。 - Authorization Header格式错误:测试中设置的
Authorization: test不符合OAuth2客户端凭证模式的Basic认证规范,Postman可能正确使用了Base64编码的凭证,而测试中的错误格式也可能导致请求异常。
解决方案
- 初始化MockMvc时应用Spring Security配置:导入
SecurityMockMvcConfigurers.springSecurity(),在构建MockMvc时应用该配置,确保Spring Security的过滤器链被加载,端点能正确映射。 - 移除无用的@Mock注解:删除测试类中未使用的
@Mock注解和相关静态导入,避免干扰Spring上下文。 - 修正Authorization Header格式:客户端凭证模式下,
Authorizationheader需要使用Basic认证,格式为Basic {base64(client_id:client_secret)},比如test:test的Base64编码是dGVzdDp0ZXN0,所以header值应为Basic dGVzdDp0ZXN0。同时,客户端凭证模式下无需在请求参数中传递client_id和client_secret(已通过Header传递)。
修改后的测试代码
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest class AuthorizationServerTests { @Autowired private WebApplicationContext context; private MockMvc mockMvc; @BeforeEach void setup() { // 应用Spring Security配置初始化MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context) .apply(SecurityMockMvcConfigurers.springSecurity()) .build(); } @Test void testTokenEndpoint() throws Exception { mockMvc.perform(post("/oauth2/token") .header("Authorization", "Basic dGVzdDp0ZXN0") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .param("grant_type", "client_credentials") .param("scope", "read")) .andExpect(status().isOk()) .andExpect(jsonPath("$.access_token").exists()); } }
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

