如何避免 https spring 安全单元测试的 302 响应?

How to avoid 302 response on https spring security unit test?

我有 java Spring 安全应用程序(使用 jhipster 构建),我正在尝试添加一些单元测试,以根据当前经过身份验证的用户测试逻辑。

为此,我配置了 MockMvc 对象以使用 Web 应用程序上下文和 spring 安全性:

@Test
@Transactional
public void getAllContacts() throws Exception {
    restContactMockMvc = MockMvcBuilders
        .webAppContextSetup(context)
        .apply(springSecurity())
        .build();
    restContactMockMvc.perform(get("/api/contacts")).andExpect(status().isOk());
}

问题是我还将应用程序配置为需要 HTTPS,每当我 运行 这个单元测试时,我都会收到 302 重定向响应,因为它似乎在尝试发送 HTTP 请求而不是HTTPS.

我强制使用 HTTPS 的方式是 SecurityConfiguration.configure(HttpSecurity http) 中的以下行:

if (env.acceptsProfiles("!dev"))http.requiresChannel().anyRequest().requiresSecure();

所以,我的问题是如何让我的单元测试正确地达到 运行?可能是通过发送模拟 HTTPS 请求,或者在 运行 进行单元测试时禁用 HTTPS?

我正在用我已经开始使用的修复程序回答我自己的问题,希望这可以帮助其他人。我仍然愿意接受其他更好的解决方案。

SecurityConfiguration.configure(HttpSecurity http) 方法中,我修改了 if 语句,如果我们是 运行 集成测试,则强制 https 跳过它:

if (env.acceptsProfiles("!dev") && !((StandardEnvironment) env).getPropertySources().contains("integrationTest")) {
        http.requiresChannel().anyRequest().requiresSecure();
}

使用 Springs MockMvc 东西,您还可以指定要使用 secure(true) 方法发送模拟 HTTPS 请求,如下所示:

restContactMockMvc.perform( get("/api/contacts").secure( true ) ).andExpect( status().isOk() )

除了@rhinds 的正确答案之外,您还可以将此代码添加到您的 @Before 方法中,以使所有调用在默认情况下都是安全的:

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext;

public class YourTestClass {
    @Autowired
    private Filter springSecurityFilterChain;
    @Autowired
    private SecurityTestController securityTestController;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = standaloneSetup(securityTestController)
            .addFilters(springSecurityFilterChain)
            .defaultRequest(get("/").secure(true).with(testSecurityContext()))
            .build();
    }

    // Your Tests Here

    @Test
    public void httpsRedirect() throws Exception {
        mockMvc.perform(get("/").secure(false))
            .andExpect(status().isFound())
            .andExpect(result -> StringUtils.isNotEmpty(result.getResponse().getHeader("Location")))
            .andExpect(result -> result.getResponse().getHeader("Location").startsWith("https://"));
    }
}