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

如何在JUnit5测试代码中向API控制器传递Session?

Spring Boot OAuth2 测试时无法将Session用户传递到控制器

开发环境

  • Java 11
  • Spring Boot 2.7.2
  • Gradle
  • JUnit5
  • Spring Security & OAuth2

问题描述

业务逻辑正常:OAuth2认证用户发布帖子时,会基于Session中的用户信息注册作者,但JUnit5测试无法将Session传递到API控制器,尝试三种方法均失败:

  • @WithMockUser(roles = "USER") + MockHttpSession → Session为null
  • 仅用MockHttpSession → 302重定向到/login
  • @WithSecurityContext → 403禁止错误

测试代码:

@AutoConfigureMockMvc
@SpringBootTest
@WithMockUser(roles = "USER")
class PostApiControllerTest {
    @DisplayName("save a post")
    @Test
    void save_post() throws Exception {
        //given
        User user1 = User.builder()
                .userRole(Role.USER)
                .userPicture("picture")
                .userEmail("email")
                .username("kim")
                .build();


        userRepository.save(user1);

        MockHttpSession mockHttpSession = new MockHttpSession();
        mockHttpSession.setAttribute("user", new SessionUser(user1));

        RequestAddPost post = RequestAddPost.builder()
                .title("title")
                .content("content")
                .categoryName("")
                .build();

        //then
        mockMvc.perform(post("/write")
                        .contentType(APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(post))
                        .session(mockHttpSession))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.title").value("title"))
                .andExpect(jsonPath("$.content").value("content"))
                .andDo(print());
    }
}

API控制器:

@RestController
@RequiredArgsConstructor
public class PostApiController {

    private final PostService postService;

    @PostMapping("/write")
    public ResponsePost writePost(@Validated @RequestBody RequestAddPost requestAddPost,
                                  @LoginUser SessionUser user) {
        return postService.savePost(requestAddPost, user);
    }
}

问题根源

  1. @WithMockUser会自动创建Spring Security的认证上下文和对应Session,覆盖手动设置的MockHttpSession,导致控制器无法获取存入的user属性。
  2. 仅用MockHttpSession时,请求未通过Spring Security的OAuth2认证拦截,被重定向到登录页。
  3. @WithSecurityContext未正确关联Session中的用户信息,导致权限验证失败。

解决步骤

1. 修改测试代码:移除@WithMockUser,手动添加认证并传递Session

去掉测试类上的@WithMockUser注解,改用mockMvc的with(user(...))方法添加认证信息,同时传递手动创建的MockHttpSession,确保请求既通过Security认证,又能让控制器从Session中拿到用户。

修改后的测试代码:

@AutoConfigureMockMvc
@SpringBootTest
class PostApiControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UserRepository userRepository;

    @DisplayName("保存帖子")
    @Test
    void save_post() throws Exception {
        // given
        User user1 = User.builder()
                .userRole(Role.USER)
                .userPicture("picture")
                .userEmail("email")
                .username("kim")
                .build();

        userRepository.save(user1);

        MockHttpSession mockHttpSession = new MockHttpSession();
        mockHttpSession.setAttribute("user", new SessionUser(user1));

        RequestAddPost post = RequestAddPost.builder()
                .title("title")
                .content("content")
                .categoryName("")
                .build();

        // when & then
        mockMvc.perform(post("/write")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(post))
                        .session(mockHttpSession)
                        // 添加认证信息,匹配用户角色
                        .with(user(user1.getUsername()).roles(user1.getUserRole().name())))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.title").value("title"))
                .andExpect(jsonPath("$.content").value("content"))
                .andDo(print());
    }
}

2. 确保SessionUser实现Serializable接口

Session中的对象必须实现Serializable,否则无法正确存入Session,测试时会丢失用户信息:

public class SessionUser implements Serializable {
    // 你的属性和方法
}

3. 检查Spring Security配置

确保/write端点允许认证用户访问:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                // 允许认证用户访问/write
                .antMatchers(HttpMethod.POST, "/write").authenticated()
                // 其他配置
                .and()
            // OAuth2相关配置
            .oauth2Login()
                // 你的OAuth2配置
                ...;
    }
}

原理说明

  • with(user(...))方法为请求添加Spring Security认证信息,让请求通过OAuth2拦截。
  • 手动创建的MockHttpSession被正确传递到控制器,@LoginUser注解的解析器可以从Session中获取user属性。
  • 移除@WithMockUser避免了自动创建的Session覆盖手动设置的Session。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:48:20