gpt4 book ai didi

java - Spring Boot,禁用测试安全性

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:01:39 28 4
gpt4 key购买 nike

我使用 spring boot 版本“1.3.0.M5”(我也尝试过版本“1.2.5.RELEASE”)。我添加了 spring 安全性:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

和代码:

@SpringBootApplication
public class SpringBootMainApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMainApplication.class, args);
}
}

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/sampleentity").authenticated()
.and().authorizeRequests()
.and().formLogin().permitAll()
.and().logout().permitAll().logoutUrl("/logout")
.logoutSuccessUrl("/");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

@RestController
@RequestMapping("/api/sampleentity")
public class SampleEntityController {
@RequestMapping(method= RequestMethod.GET)
public Iterable<SampleEntity> getAll() {
return ImmutableSet.of();
}
@RequestMapping(method=RequestMethod.POST)
@ResponseStatus(value= HttpStatus.CREATED)
public SampleEntity create(@RequestBody SampleEntity sampleEntity) {
return sampleEntity;
}
}

并在访问/api/sampleentity 时测试失败:org.springframework.web.client.HttpClientErrorException: 403 Forbidden (...)

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootMainApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port=0"})
public class SampleEntityTest {
@Value("${local.server.port}")
private int port;
private String url;
private RestTemplate restTemplate;
@Autowired
private ApplicationContext context;
@BeforeClass
public static void authenticate(){
//ONE TRY
// Authentication authentication =
// new UsernamePasswordAuthenticationToken("user", "password",
// AuthorityUtils.createAuthorityList("USER")); //tried "ROLE_USER"
// SecurityContextHolder.getContext().setAuthentication(authentication);
}
@Before
public void setUp() {
url = String.format("http://localhost:%s/api/sampleentity", port);
restTemplate = new RestTemplate();
//ANOTHER TRY
// AuthenticationManager authenticationManager = context.getBean(AuthenticationManager.class);
// Authentication authentication = authenticationManager
// .authenticate(new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("USER"))); //tried "ROLE_USER"
// SecurityContextHolder.getContext().setAuthentication(authentication);
}
//THIS METHOD SHOULD WORK !
@Test
//ANOTHER TRY
//@WithMockUser(username="user",password = "password", roles={"USER"})//tried "ROLE_USER"
public void testEntity_create() throws Exception {
SampleEntity sampleEntity = create("name", 1);
ResponseEntity<SampleEntity> response = restTemplate.postForEntity(url, sampleEntity, SampleEntity.class);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
}
private SampleEntity create(String name, int id) {
SampleEntity entity = new SampleEntity();
entity.setName(name);
entity.setId(id);
return entity;
}
}

当我从 main() 运行应用程序并访问 url 时: http://localhost:8080/api/sampleentity我被重定向到登录页面。

如何运行我的测试并禁用安全性或仅登录用户?

--我的解决方案:使用配置文件从测试中排除安全性:

@SpringBootApplication
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
public class SpringBootMainApplication {body the same}

@EnableWebSecurity
@Import(SecurityAutoConfiguration.class)
@Profile("!test")
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {body the same}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootMainApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port=0"})
@ActiveProfiles("test")
public class SampleEntityTest {body the same}

最佳答案

您必须对您的配置进行一些更改并进行测试才能解决您的问题。

首先,我将解释为什么您的解决方案不起作用:

  1. Spring RestTemplate 类是一种访问 REST 服务的可能方式,但在构造方式上缺少一些 header 信息(这并不意味着它不可能通过 RestTemplate).这就是身份验证不起作用的原因。
  2. 由于使用了 RestTemplate 类,我的第一个解决方案尝试没有成功,因为 RestTemplate 请求可能会创建一个新 session 。它设置了一个完全不同的环境。如果您想测试使用 @PreAuthorize 注释保护的方法,我的代码就可以使用,但前提是您想直接在测试中执行这样的方法,并且您需要有效的身份验证。
  3. 在当前的 spring 安全配置中,您无法自动授权任何用户。

其次,这是对您的代码进行的必要更改:

首先是配置类

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER" );
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().csrf().disable()
.authorizeRequests().antMatchers("/api/sampleentity").authenticated()
.and().authorizeRequests().antMatchers("/users").hasRole("ADMIN")
.and().formLogin().permitAll()
.and().logout().permitAll().logoutUrl("/logout")
.logoutSuccessUrl("/");
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

我必须添加 httpBasic 身份验证支持(以通过 http header 属性启用身份验证)并且我禁用了 csrf token (后者只是为了方便,您应该根据应用程序的关键性重新启用它们)。

然后是测试类:

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;

import javax.servlet.Filter;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootMainApplication.class)
@WebAppConfiguration
@IntegrationTest({ "server.port=0" })
public class SampleEntityTest {

private String url;
private MockMvc mockMvc;
private HttpMessageConverter mappingJackson2HttpMessageConverter;

private MediaType contentType = new MediaType(
MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));

@Autowired
private WebApplicationContext webApplicationContext;

@Autowired
private Filter springSecurityFilterChain;

@Autowired
void setConverters(HttpMessageConverter<?>[] converters) {
for (HttpMessageConverter hmc : Arrays.asList(converters)) {
if (hmc instanceof MappingJackson2HttpMessageConverter) {
this.mappingJackson2HttpMessageConverter = hmc;
}
}

Assert.assertNotNull("the JSON message converter must not be null",
this.mappingJackson2HttpMessageConverter);
}

@Before
public void setUp() {
url = "/api/sampleentity";
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilters(springSecurityFilterChain).build();
}

@Test
public void testEntityGet() throws Exception {
mockMvc.perform(
get(url)
.with(httpBasic("user", "password")))
.andExpect(status().isOk());
}

@Test
public void testEntityPost() throws Exception {
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setName("name");
sampleEntity.setId(1);
String json = json(sampleEntity);
mockMvc.perform(
post(url)
.contentType(contentType)
.content(json)
.with(httpBasic("user", "password")))
.andExpect(status().isCreated());
}

protected String json(Object o) throws IOException {
MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
this.mappingJackson2HttpMessageConverter.write(o,
MediaType.APPLICATION_JSON, mockHttpOutputMessage);
return mockHttpOutputMessage.getBodyAsString();
}

我这里使用了spring/spring security测试方式。

使用的版本:

    <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.2.RELEASE</version>
<scope>test</scope>
</dependency>

如果您想测试您的 rest api,我可以向您推荐适用于 Chrome 的 Postman 插件。因为这可以帮助您更快地确定问题。

我希望这能帮助你最终解决你的问题。

关于java - Spring Boot,禁用测试安全性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32956829/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com