如何测试Spring Security OAuth2资源服务器配置?单元与集成测试解析
针对Spring Security OAuth2资源服务器配置的测试方案
一、如何测试该配置(无需依赖外部认证服务器)
因为无法控制认证服务器,核心思路是模拟JWT令牌与认证上下文,完全脱离外部认证服务,适配CI与开发环境:
1. 用Spring Security Test快速验证权限规则
借助MockMvc和Spring Security提供的JWT模拟工具,直接构造不同权限的认证请求,验证端点的访问控制逻辑:
@SpringBootTest @AutoConfigureMockMvc class SecurityConfigTest { @Autowired private MockMvc mockMvc; // 测试私有端点:拥有api:read权限可访问 @Test void privateEndpoint_WithReadScope_ShouldAllow() throws Exception { mockMvc.perform(get("/api/v1/private/data") .with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_api:read")))) .andExpect(status().isOk()); } // 测试私有端点:无对应权限被拒绝 @Test void privateEndpoint_WithoutValidScope_ShouldDeny() throws Exception { mockMvc.perform(get("/api/v1/private/data") .with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_other:read")))) .andExpect(status().isForbidden()); } // 测试公共端点:已认证用户可访问 @Test void publicEndpoint_WithValidJwt_ShouldAllow() throws Exception { mockMvc.perform(get("/api/v1/public/info") .with(jwt())) // 模拟已认证用户 .andExpect(status().isOk()); } // 测试公共端点:未认证用户被拒绝 @Test void publicEndpoint_WithoutAuth_ShouldDeny() throws Exception { mockMvc.perform(get("/api/v1/public/info")) .andExpect(status().isUnauthorized()); } }
这里的jwt()是Spring Security Test提供的请求处理器,能快速构造认证上下文,无需真实JWT签名或认证服务器交互。
2. 自定义JWT解码器(适配严格校验场景)
如果需要验证JWT的签名、issuer等规则,可以在测试配置中替换默认解码器为模拟实现:
@TestConfiguration static class TestSecurityConfig { @Bean JwtDecoder jwtDecoder() { // 模拟JWT解码逻辑,忽略签名验证,直接返回预设权限的JWT对象 return token -> Jwt.withTokenValue(token) .header("alg", "none") .claim("scope", "api:read") .build(); } }
将该配置类通过@Import加入测试,即可模拟真实的JWT解析流程,同时避免依赖外部服务。
二、测试内容与单元/集成测试边界
1. 核心测试内容
- 端点权限匹配:验证每个端点对应的权限规则是否生效(比如
/api/v1/private/**必须拒绝无api:read/write权限的请求) - 认证状态校验:确认未认证用户无法访问公共端点,已认证用户可正常访问
- 禁用认证方式验证:验证httpBasic、formLogin等已被禁用(比如发送httpBasic请求应返回401,而非跳转登录页)
- 方法级权限校验:如果Controller方法使用了
@PreAuthorize等注解,需单独验证这些注解的规则是否生效
2. 单元测试与集成测试的边界
- 单元测试:聚焦
SecurityConfig本身的配置逻辑,验证HttpSecurity的调用链是否符合预期,比如是否正确设置了权限规则、禁用了指定认证方式。可以用Mockito模拟HttpSecurity对象:
class SecurityConfigUnitTest { private SecurityConfig securityConfig = new SecurityConfig(); @Test void filterChain_ConfiguresCorrectRules() throws Exception { HttpSecurity http = mock(HttpSecurity.class); AuthorizationManagerRequestMatcherRegistry authRegistry = mock(AuthorizationManagerRequestMatcherRegistry.class); when(http.authorizeRequests()).thenReturn(authRegistry); when(authRegistry.antMatchers("/api/v1/private/**")).thenReturn(mock(AuthorizationManagerRequestMatcherRegistry.AuthorizedUrl.class)); securityConfig.filterChain(http); // 验证配置逻辑是否正确执行 verify(authRegistry).antMatchers("/api/v1/private/**"); verify(authRegistry).antMatchers("/api/v1/public/**"); verify(http).oauth2ResourceServer(any()); verify(http).httpBasic().disable(); } }
- 集成测试:验证Spring上下文加载后,Security配置与Controller、过滤器等组件的协同工作是否正常,也就是通过
MockMvc测试真实端点的请求结果,对应第一部分的测试方案。集成测试不关心HttpSecurity的内部调用,只关注实际请求的权限控制结果是否符合预期。
内容的提问来源于stack exchange,提问作者Dmytro Chasovskyi
相关产品推荐
相关产品推荐

