如何将MockMvc中的用户关联到SecurityContextHolder
解决MockMvc GET请求Mock用户无法关联到SecurityContextHolder的问题
问题分析
你在使用@WebMvcTest测试MovieController时,通过with(user("donna"))设置的Mock用户无法被存入SecurityContextHolder,导致accountRepository.findAccountByUsername("donna")未被正确触发。核心原因是手动用standaloneSetup构建MockMvc时,绕过了Spring Security自动配置的过滤器链,缺少SecurityContextPersistenceFilter——这个过滤器负责将请求中的Mock用户信息同步到SecurityContextHolder。
解决方案
方案一:使用@Autowired自动注入MockMvc(推荐)
@WebMvcTest注解会自动配置MockMvc并集成Spring Security完整的过滤器链,不需要手动构建MockMvc,能自动处理SecurityContext的持久化逻辑。
修改后的测试代码:
@Import(SecurityConfig::class) @WebMvcTest(controllers = [MovieController::class]) class MovieControllerTests { @Autowired private lateinit var mockMvc: MockMvc @MockBean private lateinit var accountRepository: AccountRepository @MockBean private lateinit var movieRepository: MovieRepository @Test fun `does return movie queue`() { mockMvc.get("/movies/fetch-queue") { with(user("donna")) }.andExpectAll { status { isOk() } content { contentType(MediaType.APPLICATION_JSON) } } Mockito.verify(accountRepository).findAccountByUsername("donna") } }
方案二:手动添加SecurityContextPersistenceFilter(仅保留standaloneSetup时使用)
如果必须手动构建MockMvc,需要显式添加SecurityContextPersistenceFilter,确保请求中的Mock用户信息被同步到SecurityContextHolder。
修改setup方法:
@BeforeEach fun setup() { // 创建SecurityContext持久化过滤器,使用HttpSession存储上下文 val securityContextFilter = SecurityContextPersistenceFilter(HttpSessionSecurityContextRepository()) mockMvc = MockMvcBuilders.standaloneSetup(MovieController(movieRepository, accountRepository)) .apply(SecurityMockMvcConfigurers.springSecurity()) .addFilter(securityContextFilter) // 手动添加过滤器 .build() }
关键说明
with(user("donna"))本质是将Mock用户信息绑定到HttpServletRequest的属性中,SecurityContextPersistenceFilter会读取该属性并将用户信息存入SecurityContextHolder,这样控制器就能获取到当前登录用户。- 优先使用方案一,因为
@WebMvcTest的自动配置能避免手动配置过滤器链带来的遗漏和错误,测试代码更简洁且符合Spring测试规范。
内容的提问来源于stack exchange,提问作者200 OK
相关产品推荐
相关产品推荐

