我已经使用Spring Security以我的经典方式在我的控制器中设置了基本身份验证,如下所示:
@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();
}
答案 0 :(得分:5)
这种行为背后有两个原因:
@WithMockUser
注释不用于执行身份验证。它创建了一个已经过身份验证的用户。默认情况下,他的凭据为user
:password
@WebMvcTest
未执行 MySecurityConfig.java。此注释会创建Spring mockMvc对象,其默认值为进行测试。这些安全默认值由org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration
应用
您可以通过在MySecurityConfig
方法上设置断点并在调试模式下重新运行测试来仔细检查这一点。断点不会被击中。解决问题1
只需将您的方法更改为@WithMockUser注释即可。它提供已登录的用户。仍然可以通过指定具体的用户名,密码和角色来测试URL安全性和角色配置。
解决问题2
为所有Integration测试创建基类。它将配置应用了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"));
}
}
答案 1 :(得分:2)
以下是如何使用spring security的配置运行mockMVC测试:对于USER角色...
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
public class SomeControllerTest {
@Autowired
private WebApplicationContext context;
@Autowired
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.defaultRequest(get("/")
.with(user("user").password("password").roles("USER")))
.apply(springSecurity())
.build();
}
@Test
public void test1() {
mockMvc.perform(get(...)).andExpect(...);
}
}
进行此更改后,您的GET测试现在应该可以正常工作。
由于spring security为POST请求等http请求提供跨站点请求伪造保护,因此需要使用crsf()
运行这些特定测试@Test
public void shouldPost() {
mockMvc.perform(post(...)).with(csrf().asHeader())
.andExpect(...);
}
答案 2 :(得分:0)
有关信息,此代码使我能够使用从application.properties文件提取的凭据成功运行凭据测试,而无需使用@WithMockUser批注。
@Autowired
MockMvc mvc;
@Autowired
private WebApplicationContext context;
@MockBean
BookRepository bookRepository;
@Test
public void testFindAll() throws Exception {
mvc = MockMvcBuilders.webAppContextSetup(context).build();
this.mvc.perform(get("/books").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
答案 3 :(得分:0)
我遇到了同样的问题。我可以使用具有指定权限的@WithMockUser注释来解决此问题。
$sql = "SELECT user_id, name, count(user_id) as msgs_count from table group by (user_id, name)";
$result = $mysqli->query($query)
while ($user = mysqli_fetch_assoc($users)) {
$user_id = $users['user_id'];
$msgs_count= $users['msgs_count'];
$count[$user_id] = $msgs_count;
echo "{$user['name']} messages: $msgs_count";
}