首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >弹簧启动,禁用测试安全性。

弹簧启动,禁用测试安全性。
EN

Stack Overflow用户
提问于 2015-10-05 19:54:58
回答 2查看 22.2K关注 0票数 13

我使用spring引导版本"1.3.0.M5“(我还尝试了版本"1.2.5.RELEASE")。我增加了spring的安全性:

代码语言:javascript
复制
<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>

和代码:

代码语言:javascript
复制
@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禁忌(.)

代码语言:javascript
复制
@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时,我被重定向到登录页面。

我如何运行我的测试和禁用安全性,或只是登录用户?

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

代码语言:javascript
复制
@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}
EN

回答 2

Stack Overflow用户

发布于 2015-10-06 08:34:00

您必须对配置和测试进行一些更改,以解决问题。

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

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

第二,下面是对代码的必要更改:

首先是配置类。

代码语言:javascript
复制
@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头属性启用身份验证),我禁用了csrf令牌(后者只是为了方便起见,您应该根据应用程序的关键程度重新启用它们)。

其次是Testclass:

代码语言:javascript
复制
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安全测试方法。

使用的版本:

代码语言:javascript
复制
    <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,我可以推荐你Chrome的Postman插件。因为这可以帮助您更快地发现问题。

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

票数 3
EN

Stack Overflow用户

发布于 2019-08-18 15:20:33

如果您想查看自动配置的内容,请启动web应用程序并访问autoconfig端点(例如,http://localhost:8080/autoconfig)。然后搜索“Security”以查看正在检测到的“AutoConfiguration”类。

然后,可以通过排除以下这些类来禁用安全的自动配置:

代码语言:javascript
复制
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, ManagementSecurityAutoConfiguration.class })

当然,您不会希望将它们排除在生产部署之外。因此,您需要有一个单独的@Configuration类来进行生产和测试。

如果您想要一个详细的答案,请执行以下步骤:

将注释@Profile(value = {"development", "production"})添加到我的WebSecurityConfigurerAdapter实现中

代码语言:javascript
复制
@Configuration
    @EnableWebSecurity
    @Profile(value = {"development", "production"})
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

现在,在测试/资源中,创建application-test.yml来定义测试配置文件的属性,并添加以下内容-

代码语言:javascript
复制
# Security enable/disable
security:
  basic:
    enabled: false

现在,在测试用例中添加这个注释来应用active profile @ActiveProfiles(value = " test ")。我的课是这样的-

代码语言:javascript
复制
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@ActiveProfiles(value = "test")
@IntegrationTest({"server.port=0"})
public class SampleControllerIntegrationTest {

这样做将禁用测试的安全性。祝你好运!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32956829

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档