MockMvc模拟OAuth2 Token失效,请求Token触发access_denied错误
解决Spring OAuth2 API测试中MockMvc调用出现access_denied的问题
从你描述的问题来看,你已经搞定了OAuth2RestTemplate的Bean注入问题,但现在用MockMvc调用受OAuth2保护的接口时触发了access_denied错误——核心原因是测试环境里没正确模拟OAuth2的认证流程,导致请求尝试获取访问令牌时直接失败。下面给你几个针对性的解决方案:
方案1:用Spring Security Test模拟已认证的OAuth2用户
Spring Security Test自带了MockMvc的扩展能力,可以直接模拟OAuth2登录状态,完全不用实际去请求令牌。
首先给测试类加上必要的注解:
@SpringBootTest @AutoConfigureMockMvc public class TokenControllerTest { @Autowired private MockMvc mockMvc; // 测试方法写在这里 }
然后在测试方法里用oauth2Login()处理器模拟登录状态:
@Test void getAuthenticationInfo_Success() throws Exception { mockMvc.perform(get("/getAuthenticationInfo") // 一键模拟OAuth2登录后的状态 .with(SecurityMockMvcRequestPostProcessors.oauth2Login())) .andExpect(status().isOk()); }
如果需要自定义用户信息(比如用户ID、权限、个人属性),可以手动构建认证令牌:
@Test void getAuthenticationInfo_CustomUser() throws Exception { // 自定义用户属性 Map<String, Object> userAttributes = Map.of( "sub", "test-user-123", "name", "Miguel Costa", "email", "test@example.com" ); DefaultOAuth2User oauth2User = new DefaultOAuth2User( Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")), userAttributes, "sub" // 指定用户标识字段 ); // 构建完整的OAuth2认证令牌 OAuth2AuthenticationToken authToken = new OAuth2AuthenticationToken( oauth2User, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")), "your-registration-id" // 对应你配置的客户端注册ID ); mockMvc.perform(get("/getAuthenticationInfo") .with(SecurityMockMvcRequestPostProcessors.authentication(authToken))) .andExpect(status().isOk()); }
方案2:模拟OAuth2RestTemplate的行为(如果接口依赖它调用外部服务)
如果你的getAuthenticationInfo接口内部会通过OAuth2RestTemplate调用其他OAuth2保护的服务,那测试时就得模拟这个模板的返回值,避免它真的去请求令牌:
@SpringBootTest @AutoConfigureMockMvc public class TokenControllerTest { @Autowired private MockMvc mockMvc; // 用@MockBean替换真实的OAuth2RestTemplate @MockBean private OAuth2RestTemplate oauthRestTemplate; @Test void getAuthenticationInfo_Success() throws Exception { // 模拟RestTemplate的调用返回结果 when(oauthRestTemplate.getForObject( anyString(), // 匹配任意请求URL eq(YourResponseClass.class) // 匹配返回的对象类型 )).thenReturn(new YourResponseClass("mock-data")); mockMvc.perform(get("/getAuthenticationInfo") .with(oauth2Login())) .andExpect(status().isOk()); } }
方案3:配置测试环境的OAuth2模拟参数(可选)
如果你的测试需要更贴近真实环境的配置,可以在src/test/resources/application.yml里加一套模拟的OAuth2客户端配置:
spring: security: oauth2: client: registration: test-client: client-id: test-client-id client-secret: test-client-secret authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/test-client" provider: test-provider: authorization-uri: https://mock-auth-server.com/oauth/authorize token-uri: https://mock-auth-server.com/oauth/token user-info-uri: https://mock-auth-server.com/userinfo user-name-attribute: sub
额外注意事项
- 确保你的测试依赖里包含Spring Security Test:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
- 检查控制器上的权限注解(比如
@PreAuthorize),确保模拟的用户拥有对应的权限。
内容的提问来源于stack exchange,提问作者Miguel Costa
相关产品推荐
相关产品推荐

