SpringBoot中@PreAuthorize接口JUnit测试表达式评估报错求助
问题根因
- 测试类中使用
@Mock注解生成的SecurityService实例仅为Mockito普通Mock对象,未注册到Spring测试上下文中,导致@PreAuthorize的SpEL表达式无法找到名为securityService的Bean,触发表达式解析失败。 - Mock规则与实际请求参数不匹配:你定义的
when(securityService.isValidUser("test.test@gmail.com"))匹配的入参是邮箱字符串,但实际测试请求中传递的id参数是789988,即使Bean能找到也会返回null触发权限校验不通过。 @WebMvcTest默认不会自动启用方法安全校验相关配置,需要额外开启注解支持。
解决方案
步骤1:替换@Mock为@MockBean
@MockBean是Spring Boot提供的测试注解,会将Mock后的实例注册到Spring上下文中,SpEL表达式可正常识别到@securityService这个Bean。
步骤2:修正Mock规则匹配实际请求参数
和你测试请求中传入的id值保持一致,或者使用Mockito的通配符匹配任意入参。
步骤3:在测试类上添加方法安全注解
如果你的项目用的是Spring Security 6+,添加@EnableMethodSecurity注解到测试类开启PreAuthorize注解支持;如果是旧版本用@EnableGlobalMethodSecurity(prePostEnabled = true)。
步骤4:补充Context配置
在@ContextConfiguration中指定你需要加载的控制器类、安全配置类,避免测试上下文缺失必要Bean。
修正后的测试代码
@WebMvcTest @EnableMethodSecurity // Spring Security 6+ 版本使用,旧版本替换为@EnableGlobalMethodSecurity(prePostEnabled = true) @ContextConfiguration(classes = {AccountController.class, SecurityConfig.class}) // 替换为你实际的控制器类、安全配置类全路径 class WebLayerTest { @Autowired private MockMvc mockMvc; // 替换@Mock为@MockBean @MockBean SecurityService securityService; @Test void accountTest() throws Exception { // 修正入参匹配请求中的id值789988,也可用anyString()匹配任意字符串 when(securityService.isValidUser("789988")).thenReturn(true); this.mockMvc.perform(MockMvcRequestBuilders.get("/account?id=789988&sec=test@123") .contentType(MediaType.APPLICATION_JSON) .header("Origin", "*")) .andDo(print()) .andExpect(status().isOk()); } }
补充说明
如果修正后仍然提示参数解析失败,可将@PreAuthorize的表达式修改为@securityService.isValidUser(#request.getParameter('id')),直接从请求对象中获取参数,避免参数名解析异常。
内容的提问来源于stack exchange,提问作者Initials
相关产品推荐
相关产品推荐

