Spring boot, disable security for tests

后端 未结 2 2048
长情又很酷
长情又很酷 2021-02-20 07:55

I use spring boot version \"1.3.0.M5\" (I also tried version \"1.2.5.RELEASE\"). I added spring security:


  org.springframework         


        
2条回答
  •  广开言路
    2021-02-20 08:50

    You have to do some changes to your config and test to solve your problem(s).

    First I'll explain why your solution isn't working:

    1. The Spring RestTemplate class is a possible way to access your REST service but lacks some header informations the way it is constructed (Which doesn't mean it's impossible with the RestTemplate). Thats why the authentication didn't work.
    2. My first solution attempt isn't working because of the usage of the RestTemplate class, as the RestTemplate request is likely to create a new session. It sets an entirely different environment. My code works if you want to test Methods secured with the @PreAuthorize annotation but only if you want to execute such a method directly in your test and you need a valid authentication.
    3. You can't automatically authorize any user as of your current spring security configuration.

    Second, here are the necessary changes to your code:

    First the configuration class

    @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();
      }
    }
    

    I had to add httpBasic Authentication support (to enable authentication via http header attribute) and I disabled csrf tokens (the latter just for convenience, you should reenable them according to criticality of your application).

    And second the Testclass:

    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();
    }
    

    }

    I have used the spring/ spring security test approach here.

    Versions used:

        
            org.springframework.boot
            spring-boot-starter-parent
            1.2.5.RELEASE
        
    
        
            org.springframework.security
            spring-security-core
            4.0.2.RELEASE
        
        
            org.springframework.security
            spring-security-web
            4.0.2.RELEASE
        
        
            org.springframework.security
            spring-security-config
            4.0.2.RELEASE
        
        
            org.springframework.security
            spring-security-test
            4.0.2.RELEASE
            test
        
    

    If you want to test your rest api i can recommend you the Postman plugin for Chrome. As that can help you identify the problem much faster.

    I hope this helps you to finally solve your problem.

提交回复
热议问题