Java 为什么Spring MockMvc结果不包含cookie?

Java 为什么Spring MockMvc结果不包含cookie?,java,spring,cookies,spring-security,mockmvc,Java,Spring,Cookies,Spring Security,Mockmvc,我试图在RESTAPI中对登录和安全性进行单元测试,所以我尝试尽可能地模拟现实生活中的请求序列 我的第一个要求是: this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac). addFilters(springSecurityFilterChain).build(); this.mapper = new ObjectMapper(); .... MvcResult result=mockMvc.perform(get("/lo

我试图在RESTAPI中对登录和安全性进行单元测试,所以我尝试尽可能地模拟现实生活中的请求序列

我的第一个要求是:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).
    addFilters(springSecurityFilterChain).build();
this.mapper = new ObjectMapper();
....
MvcResult result=mockMvc.perform(get("/login/csrf")).andExpect(status().is(200)).andReturn();
Cookie[] cookies = result.getResponse().getCookies();
(参见上的完整课程)

我试图在这里获取cookie,以便稍后能够使用收到的CSRF令牌登录,但是
cookies
数组是空的

但是,如果我运行应用程序并调用

curl -i http://localhost:8080/login/csrf
我确实得到了一个Set Cookie头,可以稍后使用该Cookie(和CSRF令牌)进行身份验证


所以问题是:如何让MockMvc将cookie返回给我?

我找到了一个解决方法,使用直接从MockHttpServletRequest提取会话对象的功能:

session=(MockHttpSession)result.getRequest().getSession();
然后直接插入会话:

req.session(session);

我对这个解决方案不满意的原因是,如果模拟httpservlet在这方面的行为与真实的servlet不同,我如何确定它在其他情况下的行为是否与真实的servlet相同。因此,我没有测试应用程序本身,这可能会在测试中留下漏洞。

我使用RestTemplate进行cookie测试。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=webEnvironment.RANDOM\u端口)
@导入(RestTemplateWithCookies.class)
公共类应用程序测试{
@本地服务器端口
专用int端口;
@自动连线
私人环境署;
@自动连线
私有RestTemplateWithCookies restTemplate;
@试验
public void appTest()引发异常{
HttpHeaders=新的HttpHeaders();
headers.set(“Referer”,env.getProperty(“allowed_Referer”);
HttpEntity=新的HttpEntity(“参数”,标题);
ResponseEntity response=restTemplate.exchange(“http://localhost:“+端口+”/扫描?电子邮件=xxx@xxx.com,HttpMethod.GET,entity,String.class);
assertTrue(response.getStatusCode()==HttpStatus.FOUND);
HttpCookie c=restemplate.getCoookies().stream().filter(x->env.getProperty(“server.session.cookie.name”).equals(x.getName()).findAny().orElse(null);
assertTrue(c!=null);
}
}

根据p.péter的回答,a生成了此代码片段,该片段将自动获取并放回在
mockMvc
上执行的每个请求(
MockHttpServletRequestBuilder
)的会话

@Autowired
私有WebApplicationContext WebApplicationContext;
@自动连线
私有过滤器springSecurityFilterChain;
@以前
public void setUp()引发异常{
最终MockHttpServletRequestBuilder defaultRequestBuilder=get(“/dummy path”);
this.mockMvc=MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
.defaultRequest(defaultRequestBuilder)
.alwaysDo(结果->setSessionBackOnRequestBuilder(defaultRequestBuilder,result.getRequest())
.apply(springSecurity(springSecurityFilterChain))
.build();
}
私有MockHttpServletRequestSetSessionBackOnRequestBuilder(最终MockHttpServletRequestBuilder requestBuilder,
最终MockHttpServletRequest(请求){
session((MockHttpSession)request.getSession());
返回请求;
}

详细回答:检查此解决方案(答案适用于spring 4):

您是如何设置
mockMvc
?@SotiriosDelimanolis我编辑了问题中的代码以显示这一点。当我有时间时,我会将测试类的相关位放在这里或pastebin上。我的测试类的相关部分在pastebin上:这与登录验证中使用的会话不同。更正。要检查会话是否存在,请使用
result.getRequest().getSession(false)
,否则,如果会话不存在,将创建会话。
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Import(RestTemplateWithCookies.class)
public class ApplicationTest {

    @LocalServerPort
    private int port;

    @Autowired
    private Environment env;

    @Autowired
    private RestTemplateWithCookies restTemplate;

    @Test
    public void appTest() throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Referer", env.getProperty("allowed_referer"));
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange("http://localhost:" + port + "/scan?email=xxx@xxx.com", HttpMethod.GET, entity, String.class);
        assertTrue(response.getStatusCode() == HttpStatus.FOUND);
        HttpCookie c = restTemplate.getCoookies().stream().filter(x -> env.getProperty("server.session.cookie.name").equals(x.getName())).findAny().orElse(null);
        assertTrue(c != null);

    }

}