我已经使用 Spring Security 以经典方式在我的 Controller 中设置了基本身份验证,如下所示:
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("user").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(....);
}
}
说到测试点,我使用的是 @WithMockUser 注释我的测试。 GET 的测试可能如下所示:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
public class SomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void test1() {
mockMvc.perform(get(...)).andExpect(...);
}
或者像这样的POST:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
public class SomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void test1() {
mockMvc.perform(post(...)).andExpect(...);
}
然后发生了意想不到的事情:
问题 : 这是怎么回事?如何纠正这种错误行为?
看起来 Spring Security 已激活,但是我的测试未使用我希望使用的身份验证。我是否必须自己模拟身份验证数据?
编辑 完整的配置方法如下
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(URL1).hasAnyRole(ROLE_ADMIN)
.antMatchers(URL2).hasAnyRole(ROLE_USER)
.antMatchers(URL3).permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
最佳答案
这种行为背后有两个原因:
@WithMockUser
注释不用于执行身份验证。它创建一个已经过身份验证的用户。默认情况下,他的凭据是 user
:password
@WebMvcTest
不执行 MySecurityConfig.java。 这个注解创建了 Spring mockMvc 对象 具有安全默认值 用于检测。这些安全默认值由 org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration
应用您可以通过在
MySecurityConfig
上放置断点来仔细检查这一点。方法并在 Debug模式下重新运行您的测试。断点未命中。 解决问题 1
只需将您的方法更改为 @WithMockUser 注释的作用。它给已经登录的用户。仍然可以通过指定具体的用户名、密码和角色来测试 url 安全性和角色配置。
解决问题 2
为所有集成测试创建一个基类。它将在应用 Spring Security 的情况下配置 mockMvc。另请注意
@SpringBootTest
注解。现在测试 将使用 MySecurityConfig.java
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class IT {
@Autowired
protected WebApplicationContext wac;
@Autowired
private FilterChainProxy springSecurityFilterChain;
protected MockMvc mockMvc;
@Before
public void applySecurity() {
this.mockMvc = webAppContextSetup(wac)
.apply(springSecurity(springSecurityFilterChain))
.build();
}
}
像这样重写测试。假设您使用 http 基本身份验证。证书在测试中提供。注意:没有模拟用户注释。
package com.example.demo;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import org.junit.Test;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
public class SomeControllerIT extends IT {
@Test
public void test1() throws Exception {
mockMvc.perform(get("/some")
.with(httpBasic("user", "user")))
.andExpect(MockMvcResultMatchers.content().string("hello"));
}
}
关于spring - @WithMockUser 不选择 Spring Security 身份验证凭据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47596283/