You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

响应式Spring中服务类@PreAuthorize注解在测试用例中未生效

@PreAuthorize注解未触发评估的常见遗漏点

核心根因

  • 测试用@InjectMockKs直接构造了FooServiceImpl的原始实例,这个实例根本没有经过Spring的AOP代理。Spring Security的方法权限拦截完全依赖为容器内的Bean生成代理对象,在方法调用前插入校验逻辑,直接调用原始对象的方法时,所有安全注解都会被完全跳过,自然不会抛出AccessDeniedException。
  • 测试上下文没有将FooServiceImpl注册为Spring Bean:当前测试仅导入了安全配置类,容器中压根不存在这个服务实例,就算去掉手动注入的逻辑,也不会为这个类生成带权限拦截的代理对象。
  • 之前尝试添加的@EnableGlobalMethodSecurity确实是多余配置:这个注解是Servlet/MVC栈的方法安全配置,和WebFlux栈使用的@EnableReactiveMethodSecurity是两套独立实现,混合添加反而可能引发Bean冲突,确实不需要额外配置。

修复方案

  1. 替换@InjectMockKs的手动实例化逻辑,改为从Spring容器中获取被代理后的服务Bean
  2. 将FooServiceImpl加入测试上下文的注册范围,确保容器能正常为其生成代理对象
    调整后的测试代码参考:
    @ExtendWith(SpringExtension::class, MockKExtension::class)
    @Import(TestSecurityConfig::class)
    // 显式注册被测服务类,纳入容器管理
    @ContextConfiguration(classes = [FooServiceImpl::class, TestSecurityConfig::class])
    internal class FooServiceImplTest {
      // 注入容器生成的代理Bean,而非手动构造的原始实例
      @Autowired
      lateinit var fooService: FooService
    
      @Test
      fun shouldDeny() {
        runBlocking {
          // 精准匹配预期抛出的权限异常类型
          assertThrows<AccessDeniedException> {
            fooService.bar()
          }
        }
      }
    }
    
  3. 注意版本适配:你的被测方法是Kotlin suspend协程方法,需要Spring Security 6.0及以上版本才能原生支持协程方法的权限切面,低版本的Reactive方法安全组件识别不了suspend函数的切点,也会导致注解不生效。

测试过程中如果需要Mock被测类的依赖,应该用@MockBean/@SpyBean的方式注册Mock对象,不要直接用@InjectMockKs手动构造整个被测实例,不然会完全绕过容器的代理增强逻辑。

内容的提问来源于stack exchange,提问作者Stuck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.24 14:24:08